Files
2026-07-13 12:32:25 +08:00

348 lines
11 KiB
Go

// Copyright 2024 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 TestDomain(t *testing.T) {
RunScripts(t, []ScriptTest{
{
Name: "create domain",
SetUpScript: []string{},
Assertions: []ScriptTestAssertion{
{
Query: `CREATE DOMAIN year AS integer CONSTRAINT not_null_c NOT NULL CONSTRAINT null_c NULL;`,
ExpectedErr: `conflicting NULL/NOT NULL constraints`,
},
{
Query: `CREATE DOMAIN year AS integer NULL NOT NULL;`,
ExpectedErr: `conflicting NULL/NOT NULL constraints`,
},
{
Query: `CREATE DOMAIN year AS integer DEFAULT 1999 NOT NULL CONSTRAINT year_check CHECK (((VALUE >= 1901) AND (VALUE <= 2155)));`,
Expected: []sql.Row{},
},
{
Query: `CREATE DOMAIN year AS integer CONSTRAINT year_check CHECK (((VALUE >= 1901) AND (VALUE <= 2155)));`,
ExpectedErr: `type "year" already exists`,
},
{
Query: `CREATE DOMAIN year_with_check AS integer CONSTRAINT year_check CHECK (((VALUE >= 1901) AND (VALUE <= 2155)));`,
Expected: []sql.Row{},
},
{
Query: `CREATE DOMAIN year_with_two_checks AS integer CONSTRAINT year_check_min CHECK (VALUE >= 1901) CONSTRAINT year_check_max CHECK (VALUE <= 2155);`,
Expected: []sql.Row{},
},
{
Query: `CREATE TABLE test_table (id int primary key, v non_existing_domain);`,
ExpectedErr: `type "non_existing_domain" does not exist`,
},
{
Query: `SELECT conname, contype, conrelid, contypid from pg_constraint WHERE conname IN ('year_check', 'year_check_min', 'year_check_max') ORDER BY conname;`,
Expected: []sql.Row{
{"year_check", "c", 0, 2637102637},
{"year_check", "c", 0, 1287570634},
{"year_check_max", "c", 0, 2938087575},
{"year_check_min", "c", 0, 2938087575},
},
},
},
},
{
Name: "multiple checks",
SetUpScript: []string{},
Assertions: []ScriptTestAssertion{
{
Query: `CREATE DOMAIN d1 AS integer CONSTRAINT check1 CHECK (VALUE > 100) CONSTRAINT check2 CHECK (VALUE < 200);`,
},
{
Query: `SELECT conname, contype, conrelid, contypid from pg_constraint WHERE conname IN ('check1', 'check2') ORDER BY conname;`,
Expected: []sql.Row{
{"check1", "c", 0, 2005192443},
{"check2", "c", 0, 2005192443},
},
},
{
Query: "create table t1 (pk int primary key, v d1);",
},
{
Query: "insert into t1 values (1, 50);",
ExpectedErr: "constraint \"check1\"",
},
{
Query: "insert into t1 values (2, 150);",
},
{
Query: "insert into t1 values (3, 250);",
ExpectedErr: "constraint \"check2\"",
},
{
Query: "CREATE DOMAIN d2 AS integer CHECK (VALUE > 300) CHECK (VALUE < 400);",
},
{
Query: `SELECT conname, contype, conrelid, contypid from pg_constraint WHERE conname IN ('d2_check', 'd2_check1') ORDER BY conname;`,
Expected: []sql.Row{
{"d2_check", "c", 0, 1691630863},
{"d2_check1", "c", 0, 1691630863},
},
},
{
Query: "CREATE DOMAIN d3 AS integer CONSTRAINT d3_check1 CHECK (VALUE > 300) CHECK (VALUE < 400);",
},
{
// TODO: this is slightly different behavior from Postgres, but the important thing is two different names are generated
Query: `SELECT conname, contype, conrelid, contypid from pg_constraint WHERE conname IN ('d3_check1', 'd3_check') ORDER BY conname;`,
Expected: []sql.Row{
{"d3_check", "c", 0, 2529148428},
{"d3_check1", "c", 0, 2529148428},
},
},
},
},
{
Name: "create table with domain type",
SetUpScript: []string{
`CREATE DOMAIN year AS integer CONSTRAINT year_check CHECK (((VALUE >= 1901) AND (VALUE <= 2155)));`,
},
Assertions: []ScriptTestAssertion{
{
Query: `CREATE TABLE table_with_domain (pk int primary key, y year);`,
Expected: []sql.Row{},
},
{
Query: `INSERT INTO table_with_domain VALUES (1, 1999)`,
Expected: []sql.Row{},
},
{
Query: `INSERT INTO table_with_domain VALUES (2, 1899)`,
ExpectedErr: `constraint "year_check"`,
},
{
Query: `SELECT * FROM table_with_domain`,
Expected: []sql.Row{{1, 1999}},
},
},
},
{
Name: "create table with domain type with default value",
SetUpScript: []string{
`CREATE DOMAIN year AS integer DEFAULT 2000;`,
`CREATE TABLE table_with_domain_with_default (pk int primary key, y year);`,
`INSERT INTO table_with_domain_with_default VALUES (1, 1999)`,
},
Assertions: []ScriptTestAssertion{
{
Query: `INSERT INTO table_with_domain_with_default(pk) VALUES (2)`,
Expected: []sql.Row{},
},
{
Query: `SELECT * FROM table_with_domain_with_default`,
Expected: []sql.Row{{1, 1999}, {2, 2000}},
},
},
},
{
Name: "create table with domain type with not null constraint",
SetUpScript: []string{
`CREATE DOMAIN year AS integer NOT NULL;`,
`CREATE TABLE tbl_not_null (pk int primary key, y year);`,
`INSERT INTO tbl_not_null VALUES (1, 1999)`,
},
Assertions: []ScriptTestAssertion{
{
// TODO: the correct error msg: `domain year does not allow null values`
Query: `INSERT INTO tbl_not_null VALUES (2, null)`,
ExpectedErr: `column name 'y' is non-nullable but attempted to set a value of null`,
},
{
// TODO: the correct error msg: `domain year does not allow null values`
Query: `INSERT INTO tbl_not_null(pk) VALUES (2)`,
ExpectedErr: `Field 'y' doesn't have a default value`,
},
{
Query: `SELECT * FROM tbl_not_null`,
Expected: []sql.Row{{1, 1999}},
},
},
},
{
Name: "update on table with domain type",
SetUpScript: []string{
`CREATE DOMAIN year AS integer NOT NULL CONSTRAINT year_check_min CHECK (VALUE >= 1901) CONSTRAINT year_check_max CHECK (VALUE <= 2155);`,
`CREATE TABLE test_table (pk int primary key, y year);`,
`INSERT INTO test_table VALUES (1, 1999), (2, 2000)`,
},
Assertions: []ScriptTestAssertion{
{
Query: `UPDATE test_table SET y = 1902 WHERE pk = 1;`,
Expected: []sql.Row{},
},
{
Query: `UPDATE test_table SET y = 1900 WHERE pk = 1;`,
ExpectedErr: `constraint "year_check_min"`,
},
{
// TODO: the correct error msg: `domain year does not allow null values`
Query: `UPDATE test_table SET y = null WHERE pk = 1;`,
ExpectedErr: `column name 'y' is non-nullable but attempted to set a value of null`,
},
{
Query: `SELECT * FROM test_table`,
Expected: []sql.Row{{1, 1902}, {2, 2000}},
},
},
},
{
Name: "domain type as text type",
SetUpScript: []string{
`CREATE DOMAIN non_empty_string AS text NULL CONSTRAINT name_check CHECK (VALUE <> '');`,
`CREATE TABLE non_empty_string_t (id int primary key, first_name non_empty_string, last_name non_empty_string);`,
`INSERT INTO non_empty_string_t VALUES (1, 'John', 'Doe')`,
},
Assertions: []ScriptTestAssertion{
{
Query: `INSERT INTO non_empty_string_t VALUES (2, 'Jane', 'Doe')`,
Expected: []sql.Row{},
},
{
Query: `UPDATE non_empty_string_t SET last_name = '' WHERE first_name = 'Jane'`,
ExpectedErr: `Check constraint "name_check" violated`,
},
{
Query: `UPDATE non_empty_string_t SET last_name = NULL WHERE first_name = 'Jane'`,
Expected: []sql.Row{},
},
{
Query: `SELECT * FROM non_empty_string_t`,
Expected: []sql.Row{{1, "John", "Doe"}, {2, "Jane", nil}},
},
},
},
{
Name: "drop domain",
SetUpScript: []string{
`CREATE DOMAIN year AS integer CONSTRAINT year_check CHECK (((VALUE >= 1901) AND (VALUE <= 2155)));`,
`CREATE TABLE table_with_domain (pk int primary key, y year);`,
},
Assertions: []ScriptTestAssertion{
{
Query: `DROP DOMAIN year;`,
ExpectedErr: `cannot drop type year because other objects depend on it`,
},
{
Query: `DROP TABLE table_with_domain;`,
Expected: []sql.Row{},
},
{
Query: `DROP DOMAIN year;`,
Expected: []sql.Row{},
},
{
Query: `DROP DOMAIN IF EXISTS year;`,
Expected: []sql.Row{},
},
{
Query: `DROP DOMAIN IF EXISTS postgres.public.year;`,
Expected: []sql.Row{},
},
{
Query: `DROP DOMAIN IF EXISTS mydb.public.year;`,
ExpectedErr: `DROP DOMAIN is currently only supported for the current database`,
},
{
Query: `DROP DOMAIN non_existing_domain;`,
ExpectedErr: `type "non_existing_domain" does not exist`,
},
},
},
{
Name: "domain array type column",
SetUpScript: []string{
`CREATE DOMAIN vc4 AS varchar(4);`,
`CREATE TABLE t (pk int primary key, v vc4[]);`,
},
Assertions: []ScriptTestAssertion{
{
Query: `INSERT INTO t VALUES (1, array['ab', 'cd']::vc4[]);`,
Expected: []sql.Row{},
},
{
Query: `INSERT INTO t VALUES (2, '{ef,gh}');`,
Expected: []sql.Row{},
},
{
Query: `SELECT * FROM t ORDER BY pk;`,
Expected: []sql.Row{{1, "{ab,cd}"}, {2, "{ef,gh}"}},
},
},
},
{
Name: "explicit cast to domain type",
SetUpScript: []string{
`CREATE DOMAIN year_not_null AS integer NOT NULL CONSTRAINT year_check CHECK (((VALUE >= 1901) AND (VALUE <= 2155)));`,
`CREATE TABLE test_table (year integer);`,
`INSERT INTO test_table VALUES (2000), (2024);`,
`CREATE TABLE my_table (id integer);`,
`INSERT INTO my_table VALUES (2000), (2002);`,
},
Assertions: []ScriptTestAssertion{
{
Query: `SELECT 1903::year_not_null;`,
Expected: []sql.Row{{1903}},
},
{
Query: `SELECT 1903::year_not_null::text;`,
Expected: []sql.Row{{"1903"}},
},
{
Query: `SELECT 1900::year_not_null;`,
ExpectedErr: `value for domain year_not_null violates check constraint "year_check"`,
},
{
Query: `SELECT NULL::year_not_null;`,
ExpectedErr: `domain year_not_null does not allow null values`,
},
{
Query: `SELECT year::year_not_null from test_table order by year;`,
Expected: []sql.Row{{2000}, {2024}},
},
{
Query: `INSERT INTO test_table VALUES (null);`,
},
{
Query: `SELECT year::year_not_null from test_table;`,
ExpectedErr: `domain year_not_null does not allow null values`,
},
{
Query: `SELECT id::year_not_null from my_table order by id;`,
Expected: []sql.Row{{2000}, {2002}},
},
{
Query: `INSERT INTO my_table VALUES (2156);`,
},
{
Query: `SELECT id::year_not_null from my_table;`,
ExpectedErr: `value for domain year_not_null violates check constraint "year_check"`,
},
},
},
})
}