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

392 lines
10 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 TestRecords(t *testing.T) {
RunScripts(t, []ScriptTest{
{
Name: "Record cannot be used as column type",
SetUpScript: []string{
"CREATE TABLE t2 (pk INT PRIMARY KEY, c1 VARCHAR(100));",
},
Assertions: []ScriptTestAssertion{
{
Query: "CREATE TABLE t (pk INT PRIMARY KEY, r RECORD);",
ExpectedErr: `column "r" has pseudo-type record`,
},
{
Query: "ALTER TABLE t2 ADD COLUMN c2 RECORD;",
ExpectedErr: `column "c2" has pseudo-type record`,
},
{
Query: "ALTER TABLE t2 ALTER COLUMN c1 TYPE RECORD;",
ExpectedErr: `column "c1" has pseudo-type record`,
},
{
Query: "CREATE DOMAIN my_domain AS record;",
ExpectedErr: `"record" is not a valid base type for a domain`,
},
{
Query: "CREATE SEQUENCE my_seq AS record;",
ExpectedErr: "sequence type must be smallint, integer, or bigint",
},
{
Query: "CREATE TYPE outer_type AS (id int, payload record);",
ExpectedErr: `column "payload" has pseudo-type record`,
},
},
},
{
Name: "Casting to record",
Assertions: []ScriptTestAssertion{
{
Query: "select row(1, 1)::record;",
Expected: []sql.Row{{[]any{1, 1}}},
},
},
},
{
// TODO: Wrapping table rows with ROW() is not supported yet. Planbuilder assumes the
// table alias is a column name and not a table.
Name: "ROW() wrapping table rows",
SetUpScript: []string{
"create table users (name text, location text, age int);",
"insert into users values ('jason', 'SEA', 42), ('max', 'SFO', 31);",
},
Assertions: []ScriptTestAssertion{
{
// TODO: ERROR: column "p" could not be found in any table in scope
Skip: true,
Query: "select row(p) from users p;",
Expected: []sql.Row{{`("(jason,SEA,44)")`}, {`("(max,SFO,31)")`}},
},
{
// TODO: ERROR: name resolution on this statement is not yet supported
Skip: true,
Query: "select row(p.*, 42) from users p;",
Expected: []sql.Row{{`(jason,SEA,42,42)`}, {`(max,SFO,31,42)`}},
},
{
// TODO: ERROR: (E).x is not yet supported
Skip: true,
Query: "SELECT (u).location FROM users u;",
Expected: []sql.Row{{"SEA"}, {"SFO"}},
},
},
},
{
Name: "ROW() wrapping values",
Assertions: []ScriptTestAssertion{
{
Query: "SELECT ROW(1, 2, 3) as myRow;",
Expected: []sql.Row{{[]any{1, 2, 3}}},
},
{
Query: "SELECT (4, 5, 6) as myRow;",
Expected: []sql.Row{{[]any{4, 5, 6}}},
},
{
Query: "SELECT (NULL, 'foo', NULL) as myRow;",
Expected: []sql.Row{{[]any{nil, "foo", nil}}},
},
{
Query: "SELECT (NULL, (1 > 0), 'baz') as myRow;",
Expected: []sql.Row{{[]any{nil, true, "baz"}}},
},
},
},
{
Name: "ROW() equality and comparison",
Assertions: []ScriptTestAssertion{
{
Query: "SELECT ROW(1, 'x') = ROW(1, 'x');",
Expected: []sql.Row{{"t"}},
},
{
Query: "SELECT ROW(1, 'x') = ROW(1, 'y');",
Expected: []sql.Row{{"f"}},
},
{
Query: "SELECT ROW(1, NULL) = ROW(1, 1);",
Expected: []sql.Row{{nil}},
},
{
Query: "SELECT ROW(1, 2) < ROW(1, 3);",
Expected: []sql.Row{{"t"}},
},
{
Query: "SELECT ROW(1, 2) < ROW(2, NULL);",
Expected: []sql.Row{{"t"}},
},
{
Query: "SELECT ROW(2, 2) < ROW(2, NULL);",
Expected: []sql.Row{{nil}},
},
{
Query: "SELECT ROW(2, 2, 1) < ROW(2, NULL, 2);",
Expected: []sql.Row{{nil}},
},
{
Query: "SELECT ROW(1, 2) < ROW(NULL, 3);",
Expected: []sql.Row{{nil}},
},
{
Query: "SELECT ROW(NULL, NULL, NULL) < ROW(NULL, NULL, NULL);",
Expected: []sql.Row{{nil}},
},
{
Query: "SELECT ROW(1, 2) <= ROW(1, 3);",
Expected: []sql.Row{{"t"}},
},
{
Query: "SELECT ROW(1, 2) <= ROW(1, 2);",
Expected: []sql.Row{{"t"}},
},
{
Query: "SELECT ROW(1, NULL) <= ROW(1, 2);",
Expected: []sql.Row{{nil}},
},
{
Query: "SELECT ROW(2, 1) > ROW(1, 999);",
Expected: []sql.Row{{"t"}},
},
{
Query: "SELECT ROW(2, 1) > ROW(1, NULL);",
Expected: []sql.Row{{"t"}},
},
{
Query: "SELECT ROW(2, 1) >= ROW(1, 999);",
Expected: []sql.Row{{"t"}},
},
{
Query: "SELECT ROW(2, 1) >= ROW(2, 1);",
Expected: []sql.Row{{"t"}},
},
{
Query: "SELECT ROW(NULL, 1) >= ROW(2, 1);",
Expected: []sql.Row{{nil}},
},
{
Query: "SELECT ROW(1, 2) != ROW(3, 4);",
Expected: []sql.Row{{"t"}},
},
{
Query: "SELECT ROW(1, 2) != ROW(NULL, 4);",
Expected: []sql.Row{{"t"}},
},
{
Query: "SELECT ROW(NULL, 4) != ROW(NULL, 4);",
Expected: []sql.Row{{nil}},
},
{
// TODO: IS NOT DISTINCT FROM is not yet supported
Skip: true,
Query: "SELECT ROW(1, NULL) IS NOT DISTINCT FROM ROW(1, NULL);",
Expected: []sql.Row{{"t"}},
},
{
Query: "SELECT ROW(1, '2') = ROW(1, 2::TEXT);",
Expected: []sql.Row{{"t"}},
},
{
Query: "SELECT ROW(1, 1) = ROW(1, 1);",
Expected: []sql.Row{{"t"}},
},
{
Query: "SELECT ROW(1, 1) != ROW(1, 1);",
Expected: []sql.Row{{"f"}},
},
{
Query: "SELECT ROW(1, 1) < ROW(1, 1);",
Expected: []sql.Row{{"f"}},
},
{
Query: "SELECT ROW(1, 1) <= ROW(1, 1);",
Expected: []sql.Row{{"t"}},
},
{
Query: "SELECT ROW(1, 1) > ROW(1, 1);",
Expected: []sql.Row{{"f"}},
},
{
Query: "SELECT ROW(1, 1) = ROW(1, 1);",
Expected: []sql.Row{{"t"}},
},
{
Query: "SELECT ROW(1, 2, null, 4) = ROW(null, 2, 3, 5);",
Expected: []sql.Row{{"f"}},
},
{
Query: "SELECT ROW(1, 2, null, 4) != ROW(null, 2, 3, 5);",
Expected: []sql.Row{{"t"}},
},
},
},
{
Name: "ROW() use inserting and selecting composite rows",
SetUpScript: []string{
"CREATE TYPE user_info AS (id INT, name TEXT, email TEXT);",
"CREATE TABLE accounts (info user_info);",
},
Assertions: []ScriptTestAssertion{
{
Query: "INSERT INTO accounts VALUES (ROW(1, 'alice', 'a@example.com'));",
Expected: []sql.Row{},
},
{
Query: "SELECT info FROM accounts;",
Expected: []sql.Row{{"(1,alice,a@example.com)"}},
},
{
Query: "SELECT (a.info).name FROM accounts a;",
Expected: []sql.Row{{"alice"}},
},
},
},
{
Name: "ROW() use in WHERE clause",
SetUpScript: []string{
"create table users (id int primary key, name text, email text);",
"insert into users values (1, 'John', 'j@a.com'), (2, 'Joe', 'joe@joe.com');",
},
Assertions: []ScriptTestAssertion{
{
Query: "SELECT * FROM users WHERE ROW(id, name, email) = ROW(1, 'John', 'j@a.com');",
Expected: []sql.Row{{1, "John", "j@a.com"}},
},
{
// TODO: IS NOT DISTINCT FROM is not yet supported
Skip: true,
Query: "SELECT * FROM users WHERE ROW(id, name) IS NOT DISTINCT FROM ROW(2, 'Jane');",
Expected: []sql.Row{{2, "Joe", "joe@joe.com"}},
},
},
},
{
Name: "ROW() casting and type inference",
Assertions: []ScriptTestAssertion{
{
Query: "SELECT ROW(1, 'a')::record;",
Expected: []sql.Row{{[]any{1, "a"}}},
},
{
Query: "SELECT ROW(1, 2) = ROW(1, 'two');",
ExpectedErr: "invalid input syntax",
},
{
Query: "SELECT ROW(1, 2) = ROW(1, '2');",
Expected: []sql.Row{{"t"}},
},
},
},
{
Name: "ROW() error cases and edge conditions",
SetUpScript: []string{
"create table users (id int primary key, name text, email text);",
"insert into users values (1, 'John', 'j@a.com'), (2, 'Joe', 'joe@joe.com');",
},
Assertions: []ScriptTestAssertion{
{
Query: "SELECT ROW(1, 2) = ROW(1);",
ExpectedErr: "unequal number of entries",
},
{
Query: "SELECT ROW(1, 2) = ROW(1, 2, 3);",
ExpectedErr: "unequal number of entries",
},
{
Query: "SELECT ROW(1, 2) < ROW(1);",
ExpectedErr: "unequal number of entries",
},
{
Query: "SELECT ROW(1, 2) <= ROW(1);",
ExpectedErr: "unequal number of entries",
},
{
Query: "SELECT ROW(1, 2) > ROW(1);",
ExpectedErr: "unequal number of entries",
},
{
Query: "SELECT ROW(1, 2) >= ROW(1);",
ExpectedErr: "unequal number of entries",
},
{
Query: "SELECT ROW(1, 2) != ROW(1);",
ExpectedErr: "unequal number of entries",
},
{
Query: "SELECT NULL::record IS NULL",
Expected: []sql.Row{{"t"}},
},
{
Query: "SELECT ROW(NULL) IS NULL",
Expected: []sql.Row{{"t"}},
},
{
Query: "SELECT ROW(NULL, NULL, NULL) IS NULL;",
Expected: []sql.Row{{"t"}},
},
{
Query: "SELECT ROW(NULL, 42, NULL) IS NULL;",
Expected: []sql.Row{{"f"}},
},
{
Query: "SELECT ROW(42) IS NULL",
Expected: []sql.Row{{"f"}},
},
{
Query: "SELECT ROW(NULL) IS NOT NULL;",
Expected: []sql.Row{{"f"}},
},
{
Query: "SELECT ROW(NULL, NULL) IS NOT NULL;",
Expected: []sql.Row{{"f"}},
},
{
Query: "SELECT ROW(NULL, 1) IS NOT NULL;",
Expected: []sql.Row{{"f"}},
},
{
Query: "SELECT ROW(1, 1) IS NOT NULL;",
Expected: []sql.Row{{"t"}},
},
{
Query: "SELECT ROW(42) IS NOT NULL;",
Expected: []sql.Row{{"t"}},
},
{
Query: "SELECT ROW(id, name), COUNT(*) FROM users GROUP BY ROW(id, name);",
Expected: []sql.Row{{[]any{1, "John"}, 1}, {[]any{2, "Joe"}, 1}},
},
},
},
{
Name: "ROW() nesting",
Assertions: []ScriptTestAssertion{
{
Query: "SELECT ROW(ROW(1, 'x'), true);",
Expected: []sql.Row{{[]any{[]any{1, "x"}, true}}},
},
},
},
})
}