# Some tests for RENAME TYPE.
statement ok
CREATE TYPE greeting AS ENUM ('hi', 'hello');
ALTER TYPE greeting RENAME TO newname

# After renaming, we should be able to resolve the type with the new name.
query T
SELECT 'hi'::newname
----
hi

# The array type should be renamed as well.
query T
SELECT ARRAY['hi']::_newname
----
{hi}

# Test that we can use the new name within a transaction.
statement ok
BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
ALTER TYPE newname RENAME TO renameagain

query T
SELECT 'hi'::renameagain
----
hi

statement ok
ROLLBACK

# We should be able to rename a type multiple times in a transaction.
statement ok
BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
ALTER TYPE newname RENAME TO new_name

query T
SELECT 'hi'::new_name
----
hi

statement ok
ALTER TYPE new_name RENAME TO new__name

query T
SELECT 'hi'::new__name
----
hi

statement ok
COMMIT

statement ok
ALTER TYPE new__name RENAME TO newname

# We shouldn't be able to rename into a conflicting type.
statement ok
CREATE TABLE conflict (x INT)

statement error pq: relation \"conflict\" already exists
ALTER TYPE newname RENAME TO conflict

# Renames should try and move around the array type to find a valid name.
# This creates types _why and __why.
statement ok
CREATE TYPE _why AS ENUM ('pg', 'array', 'types', 'are', 'silly')

# This should rename the array type to ___why.
statement ok
ALTER TYPE newname RENAME TO why

query T
SELECT ARRAY['hi']::___why
----
{hi}

statement ok
CREATE TYPE names AS ENUM ('james', 'johnny')

# Cannot rename a value to a value that already a member of the type.
statement error enum value johnny already exists
ALTER TYPE names RENAME VALUE 'james' TO 'johnny'

# Cannot rename a value that is not a member of the type.
statement error jim is not an existing enum value
ALTER TYPE names RENAME VALUE 'jim' TO 'jimmy'

statement ok
ALTER TYPE names RENAME VALUE 'james' to 'jimmy'

# Make sure james is renamed to jimmy.
query T
SELECT enum_range('jimmy'::names);
----
{jimmy,johnny}

# James should not be a member of names.
statement error invalid input value for enum names: "james"
SELECT 'james'::names

# Try multiple renames in a single transaction.
statement ok
BEGIN

statement ok
ALTER TYPE names RENAME VALUE 'jimmy' TO 'jim'

statement ok
ALTER TYPE names RENAME VALUE 'johnny' TO 'john'

statement ok
COMMIT

# Make sure both names were renamed and the old names are not members of names.
query T
SELECT enum_range('jim'::names);
----
{jim,john}

statement error invalid input value for enum names: "jimmy"
SELECT 'jimmy'::names

statement error invalid input value for enum names: "johnny"
SELECT 'johnny'::names

subtest add_value

# Start off with an empty enum, and add values to it.
statement ok
CREATE TYPE build AS ENUM ()

statement ok
ALTER TYPE build ADD VALUE 'c'

query T
SELECT enum_range('c'::build)
----
{c}

# Test some error cases.
statement error pq: enum value \"c\" already exists
ALTER TYPE build ADD VALUE 'c'

statement error pq: \"b\" is not an existing enum value
ALTER TYPE build ADD VALUE 'a' BEFORE 'b'

statement error pq: \"b\" is not an existing enum value
ALTER TYPE build ADD VALUE 'a' AFTER 'b'

statement ok
ALTER TYPE build ADD VALUE IF NOT EXISTS 'c'

statement ok
ALTER TYPE build ADD VALUE 'f'

query T
SELECT enum_range('c'::build)
----
{c,f}

statement ok
ALTER TYPE build ADD VALUE 'd' AFTER 'c'

query T
SELECT enum_range('c'::build)
----
{c,d,f}

statement ok
ALTER TYPE build ADD VALUE 'e' BEFORE 'f'

query T
SELECT enum_range('c'::build)
----
{c,d,e,f}

statement ok
ALTER TYPE build ADD VALUE 'a' BEFORE 'c'

query T
SELECT enum_range('c'::build)
----
{a,c,d,e,f}

statement ok
ALTER TYPE build ADD VALUE 'b' AFTER 'a'

query T
SELECT enum_range('c'::build)
----
{a,b,c,d,e,f}

# Ensure that we can't use/write an enum until it has become writeable.
statement ok
CREATE TABLE new_enum_values (x build)

statement ok
BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
ALTER TYPE build ADD VALUE 'g';
ALTER TYPE build ADD VALUE '_a' BEFORE 'a'

# _a and g shouldn't be included in any of the builtins.
query T
SELECT enum_range('c'::build)
----
{a,b,c,d,e,f}

query T
SELECT enum_first('c'::build)
----
a

query T
SELECT enum_last('c'::build)
----
f

statement error  pq: cannot use enum value \"g\": enum value is not yet public
INSERT INTO new_enum_values VALUES ('g')

statement ok
ROLLBACK

# Ensure that optimizer plan caching takes into account changes in types.
statement ok
CREATE TYPE cache AS ENUM ('lru', 'clock')

# Run the statement once to put it into the cache.
query T
SELECT 'clock'::cache
----
clock

# Now alter the type.
statement ok
ALTER TYPE cache RENAME VALUE 'clock' TO 'clock-pro'

statement error pq: invalid input value for enum cache: "clock"
SELECT 'clock'::cache

# Put another query into the cache.
query T
SELECT 'lru'::cache
----
lru

statement ok
ALTER TYPE cache RENAME TO store

statement error pq: type "cache" does not exist
SELECT 'lru'::cache

# Lastly, ensure that we error out in planning when trying to use a dropped type.
query T
SELECT 'lru'::store
----
lru

statement ok
DROP TYPE store

statement error pq: type "store" does not exist
SELECT 'lru'::store

statement ok
CREATE TYPE greetings AS ENUM('hi', 'hello', 'howdy', 'yo')

statement ok
ALTER TYPE greetings DROP VALUE 'hi'

statement error pq: invalid input value for enum greetings: "hi"
SELECT 'hi'::greetings

statement ok
CREATE TABLE use_greetings(k INT PRIMARY KEY, v greetings)

statement ok
INSERT INTO use_greetings VALUES(1, 'yo')

statement error pq: could not remove enum value "yo" as it is being used by "use_greetings"
ALTER TYPE greetings DROP VALUE 'yo'

query T
SELECT 'yo'::greetings
----
yo

# As only 'yo' is used by the table above, we should still be able to drop 'howdy'
statement ok
ALTER TYPE greetings DROP VALUE 'howdy'

query TTTT
SELECT * FROM [SHOW ENUMS] WHERE name = 'greetings'
----
public  greetings  {hello,yo}                  root

statement error pq: invalid input value for enum greetings: "howdy"
SELECT 'howdy'::greetings

statement ok
CREATE TABLE use_greetings2(k INT PRIMARY KEY, v greetings);
INSERT INTO use_greetings2 VALUES (1, 'hello')

statement error pq: could not remove enum value "hello" as it is being used by "use_greetings2"
ALTER TYPE greetings DROP VALUE 'hello'

query T
SELECT 'hello'::greetings
----
hello

# Once the use of "yo" has been removed, we should be able to remove it from the
# enum
statement ok
DELETE FROM use_greetings WHERE use_greetings.v = 'yo'

statement ok
ALTER TYPE greetings DROP VALUE 'yo'

statement error pq: invalid input value for enum greetings: "yo"
SELECT 'yo'::greetings

query TTTT
SELECT * FROM [SHOW ENUMS] WHERE name = 'greetings'
----
public  greetings  {hello}  root

statement ok
CREATE TYPE alphabets AS ENUM('a', 'b', 'c', 'd', 'e', 'f');
CREATE TABLE uses_alphabets (k INT PRIMARY KEY, v1 alphabets, v2 alphabets);
INSERT INTO uses_alphabets VALUES (1, 'a', 'a'), (2, 'b', 'c')

statement error pq: could not remove enum value "a" as it is being used by "uses_alphabets"
ALTER TYPE alphabets DROP VALUE 'a'

statement error pq: could not remove enum value "b" as it is being used by "uses_alphabets"
ALTER TYPE alphabets DROP VALUE 'b'

statement error pq: could not remove enum value "c" as it is being used by "uses_alphabets"
ALTER TYPE alphabets DROP VALUE 'c'

statement ok
DELETE FROM uses_alphabets WHERE k = 1

statement ok
ALTER TYPE alphabets DROP VALUE 'a'

# b and c are still in use, and should continue to fail.
statement error pq: could not remove enum value "b" as it is being used by "uses_alphabets"
ALTER TYPE alphabets DROP VALUE 'b'

statement error pq: could not remove enum value "c" as it is being used by "uses_alphabets"
ALTER TYPE alphabets DROP VALUE 'c'

# Test enum value dropping with view/default column expres.
statement ok
CREATE VIEW v as SELECT 'd':::alphabets;
CREATE TABLE uses_alphabets_2(k INT PRIMARY KEY, v alphabets DEFAULT 'e');

statement error pq: could not remove enum value "d" as it is being used in view "v"
ALTER TYPE alphabets DROP VALUE 'd'

statement ok
INSERT INTO uses_alphabets_2 VALUES(1);

# e was inserted as the default value, so we shouldn't be able to remove it.
statement error pq: could not remove enum value "e" as it is being used in a default expresion of "uses_alphabets_2"
ALTER TYPE alphabets DROP VALUE 'e'

statement ok
TRUNCATE uses_alphabets_2

statement error pq: could not remove enum value "e" as it is being used in a default expresion of "uses_alphabets_2"
ALTER TYPE alphabets DROP VALUE 'e'

statement ok
INSERT INTO uses_alphabets_2 VALUES(1);

statement ok
INSERT INTO uses_alphabets_2 VALUES (2, 'f')

# Dropping the column should work.
statement ok
ALTER TABLE uses_alphabets_2 DROP COLUMN v

statement ok
ALTER TYPE alphabets DROP VALUE 'f'


subtest add_drop_same_value_in_txn

statement ok
CREATE TYPE a AS ENUM('a')

statement error enum value "b" is being added, try again later
BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
ALTER TYPE a ADD VALUE 'b';
ALTER TYPE a DROP VALUE 'b';

statement ok
ROLLBACK

statement error enum value "a" is being dropped, try again later
BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
ALTER TYPE a DROP VALUE 'a';
ALTER TYPE a ADD VALUE 'a';

statement ok
ROLLBACK


statement error pq: enum value "a" is already being dropped
BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
ALTER TYPE a DROP VALUE 'a';
ALTER TYPE a DROP VALUE 'a'

statement ok
ROLLBACK

subtest if_not_exists_in_same_txn

statement error enum value "a" is being dropped, try again later
BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
ALTER TYPE a DROP VALUE 'a';
ALTER TYPE a ADD VALUE IF NOT EXISTS 'a';

statement ok
ROLLBACK

statement ok
BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
ALTER TYPE a ADD VALUE 'b';
ALTER TYPE a ADD VALUE IF NOT EXISTS 'b';
COMMIT

subtest add_rename_in_same_txn

statement error enum value "c" is being added, try again later
BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
ALTER TYPE a ADD VALUE 'c';
ALTER TYPE a RENAME VALUE 'c' TO 'new_name';

statement ok
ROLLBACK

subtest drop_rename_in_same_txn

statement error enum value "a" is being dropped
BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
ALTER TYPE a DROP VALUE 'a';
ALTER TYPE a RENAME VALUE 'a' TO 'new_name';

statement ok
ROLLBACK

# Ensure changes to the type are picked up by the array type descriptor as well.
subtest regression_58710

statement ok
CREATE TYPE ab_58710 AS ENUM ('a', 'b')

# NB: This step is important as it hydrates the array type alias based on the
# state of the underlying enum type descriptor.
statement error invalid input value for enum ab_58710: "c"
SELECT ARRAY['c']::_ab_58710

statement ok
SELECT ARRAY['a']::_ab_58710;

statement ok
ALTER TYPE ab_58710 ADD VALUE 'c';

statement ok
ALTER TYPE ab_58710 DROP VALUE 'a';

# 'c' was added to the enum above and 'a' was dropped, so the array type alias
# should reflect this.
statement ok
SELECT ARRAY['c']::_ab_58710;

statement error invalid input value for enum ab_58710: "a"
SELECT ARRAY['a']::_ab_58710

subtest regression_60004_basic

statement ok
CREATE TYPE enum_60004 AS ENUM ('a', 'b', 'c')

statement ok
CREATE TABLE t_60004 (k INT PRIMARY KEY, v enum_60004[])

statement ok
INSERT INTO t_60004 VALUES (1, ARRAY['a'])

statement error could not remove enum value "a" as it is being used by table "test.public.t_60004"
ALTER TYPE enum_60004 DROP VALUE 'a'

# Not used in a row, so this DROP should be fine.
statement ok
ALTER TYPE enum_60004 DROP VALUE 'b'

statement ok
CREATE VIEW v_60004 AS SELECT ARRAY['c']:::_enum_60004 AS v;

statement error pq: could not remove enum value "c" as it is being used in view "v_60004"
ALTER TYPE enum_60004 DROP VALUE 'c'

subtest regression_60004_complex
# Setup
statement ok
CREATE TYPE alphabets_60004 AS ENUM ('a', 'b', 'c', 'd')

statement ok
CREATE TABLE using_alphabets_60004(k INT PRIMARY KEY, v1 alphabets_60004[], v2 alphabets_60004[])

statement ok
INSERT INTO using_alphabets_60004 VALUES (1, ARRAY['a', 'b', 'c'], ARRAY['a','b']), (2, ARRAY['a', 'b', 'c'], ARRAY['a','d'])

statement ok
CREATE TABLE using_alphabets2_60004(k INT PRIMARY KEY, v1 alphabets_60004, v2 alphabets_60004[])

statement ok
INSERT INTO using_alphabets2_60004 VALUES (1, 'a', ARRAY['b', 'a'])

statement error could not remove enum value "d" as it is being used by table "test.public.using_alphabets_60004"
ALTER TYPE alphabets_60004 DROP VALUE 'd'

# Remove the row that uses 'd' in it and then try dropping.
statement ok
DELETE FROM using_alphabets_60004 WHERE k = 2

statement ok
ALTER TYPE alphabets_60004 DROP VALUE 'd'

statement error could not remove enum value "c" as it is being used by table "test.public.using_alphabets_60004"
ALTER TYPE alphabets_60004 DROP VALUE 'c'

statement error could not remove enum value "b" as it is being used by table "test.public.using_alphabets_60004"
ALTER TYPE alphabets_60004 DROP VALUE 'b'

statement ok
TRUNCATE using_alphabets_60004

statement ok
ALTER TYPE alphabets_60004 DROP VALUE 'c'

statement error could not remove enum value "a" as it is being used by "using_alphabets2_60004"
ALTER TYPE alphabets_60004 DROP VALUE 'a'

statement error could not remove enum value "b" as it is being used by table "test.public.using_alphabets2_60004"
ALTER TYPE alphabets_60004 DROP VALUE 'b'

statement ok
TRUNCATE using_alphabets2_60004

statement ok
ALTER TYPE alphabets_60004 DROP VALUE 'a'

statement ok
ALTER TYPE alphabets_60004 DROP VALUE 'b'


subtest if_not_exists

statement ok
CREATE TYPE ifNotExists AS ENUM()

# Weak isolation levels emit extra notices, so skip them.
skipif config weak-iso-level-configs
query T noticetrace
CREATE TYPE IF NOT EXISTS ifNotExists AS ENUM();
----
NOTICE: type "ifnotexists" already exists, skipping

subtest regression_64101

statement ok
CREATE TYPE reg_64101 AS ENUM('a', 'b', 'c')

statement ok
CREATE VIEW v_64101 AS SELECT ARRAY['a']:::_reg_64101

statement ok
ALTER TYPE reg_64101 DROP VALUE 'b'

statement error could not remove enum value "a" as it is being used in view "v_64101"
ALTER TYPE reg_64101 DROP VALUE 'a'

statement ok
DROP VIEW v_64101;

statement ok
CREATE VIEW v_64101 AS SELECT ARRAY['c'::reg_64101]

statement ok
ALTER TYPE reg_64101 DROP VALUE 'a'

statement error could not remove enum value "c" as it is being used in view "v_64101"
ALTER TYPE reg_64101 DROP VALUE 'c'

statement ok
CREATE TYPE typ_64101 AS ENUM('a', 'b', 'c');

statement ok
CREATE TABLE t1_64101("bob""b" typ_64101);

statement ok
CREATE TABLE t2_64101("bob""''b" typ_64101[]);

statement ok
INSERT INTO t1_64101 VALUES ('a');

statement ok
INSERT INTO t2_64101 VALUES(ARRAY['b'])

statement ok
ALTER TYPE typ_64101 DROP VALUE 'c'

statement error could not remove enum value "a" as it is being used by "t1_64101" in row: "bob""b"='a'
ALTER TYPE typ_64101 DROP VALUE 'a'

statement error could not remove enum value "b" as it is being used by table "test.public.t2_64101"
ALTER TYPE typ_64101 DROP VALUE 'b'

subtest regression_64398

statement error pgcode 42809 type "geometry" is a built-in type
ALTER TYPE sc64398.geometry RENAME TO bar

statement error pgcode 42809 type "geometry" is a built-in type
ALTER TYPE sc64398.public.geometry RENAME TO bar

statement ok
CREATE SCHEMA sc64398;

statement ok
CREATE TYPE sc64398.geometry AS ENUM()

statement ok
ALTER TYPE sc64398.geometry RENAME TO bar


# Test dropping enums used in views is disallowed.
subtest drop_enum_value_in_view

statement ok
CREATE TYPE abc AS ENUM ('a', 'b', 'c')

statement ok
CREATE VIEW abc_view AS (SELECT k FROM (SELECT 'a'::abc AS k))

statement error pq: could not remove enum value "a" as it is being used in view "abc_view"
ALTER TYPE abc DROP VALUE 'a'

statement ok
CREATE VIEW abc_view2 AS (SELECT 'a'::abc < 'b'::abc)

statement error pq: could not remove enum value "b" as it is being used in view "abc_view2"
ALTER TYPE abc DROP VALUE 'b'

statement ok
ALTER TYPE abc DROP VALUE 'c'

statement ok
CREATE TYPE bar AS ENUM ('b', 'a', 'r')

statement ok
CREATE VIEW bar_view AS (SELECT ARRAY['b'::bar])

statement error pq: could not remove enum value "b" as it is being used in view "bar_view"
ALTER TYPE bar DROP VALUE 'b'

subtest end

# This subtest ensures we receive correct error when dropping a value from an
# ENUM type when that value is used in a column of type ARRAY of the ENUM type.
subtest 110827

statement ok
CREATE TYPE typ_110827 AS ENUM ('a', 'b', 'c');

statement ok
CREATE TABLE t_110827 (i typ_110827[]);

statement ok
INSERT INTO t_110827 VALUES (ARRAY['a', 'a', 'b']);

statement ok
ALTER TYPE typ_110827 DROP VALUE 'c';

statement error pgcode 2BP01 could not remove enum value "a" as it is being used by table ".*t_110827"
ALTER TYPE typ_110827 DROP VALUE 'a';

statement error pgcode 2BP01 could not remove enum value "b" as it is being used by table ".*t_110827"
ALTER TYPE typ_110827 DROP VALUE 'b';


subtest end

# We accidentally introduced a regression formatting dependent rows out,
# which contain a reference to the type, so validate that the formatting logic
# works correctly when inaccessible columns exist. (#127136)
subtest validate_type_dependent_row

statement ok
CREATE TYPE typ_127136 AS ENUM('a', 'b', 'c');
CREATE TABLE t_127136 (x INT PRIMARY KEY);
CREATE INDEX foo ON t_127136((x*10));
ALTER TABLE t_127136 ADD COLUMN y typ_127136;
INSERT INTO t_127136 VALUES (1, 'a');

statement error pgcode 2BP01 could not remove enum value "a" as it is being used by "t_127136" in row: x=1, y='a'
ALTER TYPE typ_127136 DROP VALUE 'a';

subtest end

# Previously, we did not properly handle scanning index expressions for type
# references when removing an enum value (#127147).
subtest validate_type_in_index_expr

statement ok
CREATE TYPE typ_127147 AS ENUM ('a', 'b', 'c');
CREATE TABLE t (x TEXT PRIMARY KEY, INDEX ((x::typ_127147)));
INSERT INTO t VALUES ('a');

statement error pgcode 2BP01 could not remove enum value "a" as it is being used by "t" in row: x='a'
ALTER TYPE typ_127147 DROP VALUE 'a';

statement ok
TRUNCATE TABLE t;

statement ok
ALTER TYPE typ_127147 DROP VALUE 'a';

subtest end
