subtest ttl_expire_after_must_be_interval

statement error value of "ttl_expire_after" must be an interval
CREATE TABLE tbl (id INT PRIMARY KEY) WITH (ttl_expire_after = ' xx invalid interval xx')

subtest end

subtest ttl_expire_after_must_be_at_least_zero

statement error value of "ttl_expire_after" must be at least zero
CREATE TABLE tbl (id INT PRIMARY KEY) WITH (ttl_expire_after = '-10 minutes')

subtest end

subtest ttl_expiration_expression_must_be_string

statement error parameter "ttl_expiration_expression" requires a string value
CREATE TABLE tbl (id INT PRIMARY KEY) WITH (ttl_expiration_expression = 0)

subtest end

subtest ttl_expiration_expression_must_be_valid_expression

statement error ttl_expiration_expression "; DROP DATABASE defaultdb" must be a valid expression: at or near "EOF": syntax error
CREATE TABLE tbl (id INT PRIMARY KEY) WITH (ttl_expiration_expression = '; DROP DATABASE defaultdb')

statement error ttl_expiration_expression "now\(\), now\(\)" must be a single expression
CREATE TABLE tbl (id INT PRIMARY KEY) WITH (ttl_expiration_expression = 'now(), now()')

subtest end

subtest ttl_expiration_expression_must_be_timestamptz

statement error expected TTL EXPIRATION EXPRESSION expression to have type timestamptz, but 'id' has type int
CREATE TABLE tbl (id INT PRIMARY KEY) WITH (ttl_expiration_expression = 'id')

subtest end

# timestamptz + interval is stable, not immutable
subtest ttl_expiration_expression_volatility_stable

statement ok
CREATE TABLE tbl_ttl_expiration_expression_volatility_stable (
  id INT PRIMARY KEY,
  expire_at timestamptz
) WITH (ttl_expiration_expression = $$expire_at + '10 minutes'$$)

subtest end

subtest ttl_expire_after_or_ttl_expiration_expression_must_be_set

statement error "ttl_expire_after" and/or "ttl_expiration_expression" must be set
CREATE TABLE tbl (id INT PRIMARY KEY) WITH (ttl = 'on')

subtest end

subtest ttl_automatic_column_notice

# Weak isolation levels emit extra notices, so skip them.
skipif config weak-iso-level-configs
query T noticetrace
CREATE TABLE tbl_ttl_automatic_column (id INT PRIMARY KEY) WITH (ttl_automatic_column = 'on')
----
NOTICE: ttl_automatic_column is no longer used. Setting ttl_expire_after automatically creates a TTL column. Resetting ttl_expire_after removes the automatically created column.

# Weak isolation levels emit extra notices, so skip them.
skipif config weak-iso-level-configs
query T noticetrace
ALTER TABLE tbl_ttl_automatic_column RESET (ttl_automatic_column)
----
NOTICE: ttl_automatic_column is no longer used. Setting ttl_expire_after automatically creates a TTL column. Resetting ttl_expire_after removes the automatically created column.

subtest end

subtest ttl_range_concurrency_notice

# Weak isolation levels emit extra notices, so skip them.
skipif config weak-iso-level-configs
query T noticetrace
CREATE TABLE tbl_ttl_range_concurrency (id INT PRIMARY KEY) WITH (ttl_range_concurrency = 2)
----
NOTICE: ttl_range_concurrency is no longer configurable.

# Weak isolation levels emit extra notices, so skip them.
skipif config weak-iso-level-configs
query T noticetrace
ALTER TABLE tbl_ttl_range_concurrency RESET (ttl_range_concurrency)
----
NOTICE: ttl_range_concurrency is no longer configurable.

subtest end

subtest create_table_crdb_internal_expiration_incorrect_explicit_default

statement error expected DEFAULT expression of crdb_internal_expiration to be current_timestamp\(\):::TIMESTAMPTZ \+ '00:10:00':::INTERVAL
CREATE TABLE tbl (
  id INT PRIMARY KEY,
  crdb_internal_expiration TIMESTAMPTZ
) WITH (ttl_expire_after = '10 minutes')

subtest end

subtest create_table_crdb_internal_expiration_incorrect_explicit_on_update

statement error expected ON UPDATE expression of crdb_internal_expiration to be current_timestamp\(\):::TIMESTAMPTZ \+ '00:10:00':::INTERVAL
CREATE TABLE tbl (
  id INT PRIMARY KEY,
  crdb_internal_expiration TIMESTAMPTZ DEFAULT current_timestamp() + '10 minutes'
) WITH (ttl_expire_after = '10 minutes')

subtest end

subtest crdb_internal_functions

statement ok
CREATE TABLE crdb_internal_functions_tbl (
  id INT PRIMARY KEY
) WITH (ttl_expire_after = '10 minutes')

query T
SELECT create_statement FROM [SHOW CREATE TABLE crdb_internal_functions_tbl]
----
CREATE TABLE public.crdb_internal_functions_tbl (
  id INT8 NOT NULL,
  crdb_internal_expiration TIMESTAMPTZ NOT VISIBLE NOT NULL DEFAULT current_timestamp():::TIMESTAMPTZ + '00:10:00':::INTERVAL ON UPDATE current_timestamp():::TIMESTAMPTZ + '00:10:00':::INTERVAL,
  CONSTRAINT crdb_internal_functions_tbl_pkey PRIMARY KEY (id ASC)
) WITH (ttl = 'on', ttl_expire_after = '00:10:00':::INTERVAL)

statement ok
SELECT crdb_internal.validate_ttl_scheduled_jobs()

statement ok
SELECT crdb_internal.repair_ttl_table_scheduled_job('crdb_internal_functions_tbl'::regclass::oid)

statement ok
SELECT crdb_internal.validate_ttl_scheduled_jobs()

let $crdb_internal_functions_tbl_oid
SELECT 'crdb_internal_functions_tbl'::regclass::oid

user testuser

statement error user testuser does not have REPAIRCLUSTER system privilege
SELECT crdb_internal.repair_ttl_table_scheduled_job($crdb_internal_functions_tbl_oid)

statement error user testuser does not have REPAIRCLUSTER system privilege
SELECT crdb_internal.validate_ttl_scheduled_jobs()

user root

subtest end

subtest ttl_expire_after_required

statement ok
CREATE TABLE ttl_expire_after_required() WITH (ttl_expire_after='10 minutes')

statement error "ttl_expire_after" and/or "ttl_expiration_expression" must be set
ALTER TABLE ttl_expire_after_required RESET (ttl_expire_after)

subtest end

subtest ttl_expiration_expression_required

statement ok
CREATE TABLE ttl_expiration_expression_required(expire_at TIMESTAMPTZ) WITH (ttl_expiration_expression='expire_at')

statement error "ttl_expire_after" and/or "ttl_expiration_expression" must be set
ALTER TABLE ttl_expiration_expression_required RESET (ttl_expiration_expression)

subtest end

subtest alter_table_crdb_internal_expiration_incorrect_explicit_default

statement ok
CREATE TABLE alter_table_crdb_internal_expiration_incorrect_explicit_default() WITH (ttl_expire_after='10 minutes')

statement error cannot alter column crdb_internal_expiration while ttl_expire_after is set
ALTER TABLE alter_table_crdb_internal_expiration_incorrect_explicit_default ALTER COLUMN crdb_internal_expiration SET DEFAULT current_timestamp()

subtest end

subtest alter_table_crdb_internal_expiration_incorrect_explicit_on_update

statement ok
CREATE TABLE alter_table_crdb_internal_expiration_incorrect_explicit_on_update() WITH (ttl_expire_after='10 minutes')

statement error cannot alter column crdb_internal_expiration while ttl_expire_after is set
ALTER TABLE alter_table_crdb_internal_expiration_incorrect_explicit_on_update ALTER COLUMN crdb_internal_expiration SET ON UPDATE current_timestamp()

subtest end

subtest drop_column_crdb_internal_expiration

statement ok
CREATE TABLE drop_column_crdb_internal_expiration() WITH (ttl_expire_after='10 minutes')

statement error cannot drop column crdb_internal_expiration while ttl_expire_after is set
ALTER TABLE drop_column_crdb_internal_expiration DROP COLUMN crdb_internal_expiration

subtest end

subtest alter_column_crdb_internal_expiration_set_not_null

statement ok
CREATE TABLE alter_column_crdb_internal_expiration() WITH (ttl_expire_after='10 minutes')

statement error cannot alter column crdb_internal_expiration while ttl_expire_after is set
ALTER TABLE alter_column_crdb_internal_expiration ALTER COLUMN crdb_internal_expiration SET NOT NULL

subtest end

subtest alter_column_crdb_internal_expiration_rename

statement ok
CREATE TABLE alter_column_crdb_internal_expiration_rename() WITH (ttl_expire_after='10 minutes')

statement error cannot rename column crdb_internal_expiration while ttl_expire_after is set
ALTER TABLE alter_column_crdb_internal_expiration_rename RENAME COLUMN crdb_internal_expiration TO crdb_internal_expiration_2

subtest end

subtest reloptions

statement ok
CREATE TABLE tbl_reloptions (
  id INT PRIMARY KEY
) WITH (
  ttl_expire_after = '10 minutes',
  ttl_select_batch_size = 10,
  ttl_delete_batch_size = 20,
  ttl_select_rate_limit = 30,
  ttl_delete_rate_limit = 40,
  ttl_pause = true,
  ttl_row_stats_poll_interval = '1 minute',
  ttl_label_metrics = true,
  ttl_disable_changefeed_replication = true
)

query T rowsort
SELECT unnest(reloptions) FROM pg_class WHERE relname = 'tbl_reloptions'
----
ttl='on'
ttl_expire_after='00:10:00':::INTERVAL
ttl_select_batch_size=10
ttl_delete_batch_size=20
ttl_select_rate_limit=30
ttl_delete_rate_limit=40
ttl_pause=true
ttl_row_stats_poll_interval='1m0s'
ttl_label_metrics=true
ttl_disable_changefeed_replication=true

subtest end

subtest schedules

statement ok
CREATE TABLE tbl_schedules (
  id INT PRIMARY KEY
) WITH (ttl_expire_after = '10 minutes')

let $label_suffix
SELECT relname || ' [' || oid || ']' FROM pg_class WHERE relname = 'tbl_schedules'

query I
SELECT count(1) FROM [SHOW SCHEDULES]
WHERE label = 'row-level-ttl: $label_suffix'
----
1

let $schedule_id
SELECT id FROM [SHOW SCHEDULES] WHERE label = 'row-level-ttl: $label_suffix'

statement error cannot drop a row level TTL schedule\nHINT: use ALTER TABLE test\.public\.tbl_schedules RESET \(ttl\) instead
DROP SCHEDULE $schedule_id

subtest end

subtest existing_ttl_concurrent_schema_change

statement ok
CREATE TABLE tbl_existing_ttl_concurrent_schema_change (
  id INT PRIMARY KEY
) WITH (ttl_expire_after = '10 minutes')

statement error cannot modify TTL settings while another schema change on the table is being processed
ALTER TABLE tbl_existing_ttl_concurrent_schema_change RESET (ttl), RESET (ttl_expire_after)

statement error cannot modify TTL settings while another schema change on the table is being processed
BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
ALTER TABLE tbl_existing_ttl_concurrent_schema_change RESET (ttl);
ALTER TABLE tbl_existing_ttl_concurrent_schema_change SET (ttl_select_batch_size = 200)

statement ok
ROLLBACK

statement error cannot perform other schema changes in the same transaction as a TTL mutation
BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
ALTER TABLE tbl_existing_ttl_concurrent_schema_change RESET (ttl);
CREATE INDEX tbl_idx ON tbl_existing_ttl_concurrent_schema_change (id)

statement ok
ROLLBACK

subtest end

subtest add_ttl_concurrent_schema_change

statement ok
CREATE TABLE tbl_add_ttl_concurrent_schema_change (
   id INT PRIMARY KEY
)

statement error cannot modify TTL settings while another schema change on the table is being processed
ALTER TABLE tbl_add_ttl_concurrent_schema_change SET (ttl_expire_after = '10 minutes'), SET (ttl_select_batch_size = 200)

statement error cannot modify TTL settings while another schema change on the table is being processed
BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
ALTER TABLE tbl_add_ttl_concurrent_schema_change SET (ttl_expire_after = '10 minutes');
ALTER TABLE tbl_add_ttl_concurrent_schema_change RESET (ttl_select_batch_size)

statement ok
ROLLBACK

statement error cannot modify TTL settings while another schema change on the table is being processed
BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
CREATE INDEX tbl_idx ON tbl_add_ttl_concurrent_schema_change (id);
ALTER TABLE tbl_add_ttl_concurrent_schema_change SET (ttl_expire_after = '10 minutes');

statement ok
ROLLBACK

statement error cannot perform other schema changes in the same transaction as a TTL mutation
BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
ALTER TABLE tbl_add_ttl_concurrent_schema_change SET (ttl_expire_after = '10 minutes');
CREATE INDEX tbl_idx ON tbl_add_ttl_concurrent_schema_change (id)

statement ok
ROLLBACK

subtest end

subtest reset_ttl

statement ok
CREATE TABLE tbl_reset_ttl (
  id INT PRIMARY KEY
) WITH (ttl_expire_after = '10 minutes')

let $label_suffix
SELECT relname || ' [' || oid || ']' FROM pg_class WHERE relname = 'tbl_reset_ttl'

query I
SELECT count(1) FROM [SHOW SCHEDULES]
WHERE label = 'row-level-ttl: $label_suffix'
----
1

# Cannot reset TTL with SET (ttl = off)
statement error setting "ttl = 'off'" is not permitted
ALTER TABLE tbl_reset_ttl SET (ttl = 'off')

# Test when we drop the TTL, ensure column is dropped and the scheduled job is removed.
statement ok
ALTER TABLE tbl_reset_ttl RESET (ttl)

query T
SELECT create_statement FROM [SHOW CREATE TABLE tbl_reset_ttl]
----
CREATE TABLE public.tbl_reset_ttl (
  id INT8 NOT NULL,
  CONSTRAINT tbl_reset_ttl_pkey PRIMARY KEY (id ASC)
)

statement ok
SELECT crdb_internal.validate_ttl_scheduled_jobs()

query I
SELECT count(1) FROM [SHOW SCHEDULES]
WHERE label = 'row-level-ttl: $label_suffix'
----
0

subtest end

# Ensure that SHOW SCHEDULES's label column is updated to reflect the new table
# name.
subtest rename_table

statement ok
CREATE TABLE tbl_rename (
  id INT PRIMARY KEY
) WITH (ttl_expire_after = '10 minutes')

let $label_suffix
SELECT relname || ' [' || oid || ']' FROM pg_class WHERE relname = 'tbl_rename'

query I
SELECT count(1) FROM [SHOW SCHEDULES]
WHERE label = 'row-level-ttl: $label_suffix'
----
1

statement ok
ALTER TABLE tbl_rename RENAME TO tbl_renamed

query I
SELECT count(1) FROM [SHOW SCHEDULES]
WHERE label = 'row-level-ttl: $label_suffix'
----
0

let $label_suffix
SELECT relname || ' [' || oid || ']' FROM pg_class WHERE relname = 'tbl_renamed'

query I
SELECT count(1) FROM [SHOW SCHEDULES]
WHERE label = 'row-level-ttl: $label_suffix'
----
1

subtest end

subtest rename_table_legacy_label

statement ok
CREATE TABLE tbl_rename_legacy_label (
  id INT PRIMARY KEY
) WITH (ttl_expire_after = '10 minutes')

let $label_suffix
SELECT relname || ' [' || oid || ']' FROM pg_class WHERE relname = 'tbl_rename_legacy_label'

query I
SELECT count(1) FROM [SHOW SCHEDULES]
WHERE label = 'row-level-ttl: $label_suffix'
----
1

# Simulate a "legacy" label to ensure that it will be appropriately updated
# when the table is renamed.
statement ok
UPDATE system.scheduled_jobs SET schedule_name = 'row-level-ttl-1234' WHERE schedule_name = 'row-level-ttl: $label_suffix';

statement ok
ALTER TABLE tbl_rename_legacy_label RENAME TO tbl_renamed2

let $label_suffix
SELECT relname || ' [' || oid || ']' FROM pg_class WHERE relname = 'tbl_renamed2'

# Legacy label no longer exists.
query I
SELECT count(1) FROM [SHOW SCHEDULES]
WHERE label = 'row-level-ttl-1234'
----
0

# Renamed and new formatted label is showing up as expected.
query I
SELECT count(1) FROM [SHOW SCHEDULES]
WHERE label = 'row-level-ttl: $label_suffix'
----
1
subtest end

subtest drop_table

# Ensure schedules are removed on DROP TABLE.
statement ok
CREATE TABLE tbl_drop_table (
  id INT PRIMARY KEY
) WITH (ttl_expire_after = '10 minutes')


let $label_suffix
SELECT relname || ' [' || oid || ']' FROM pg_class WHERE relname = 'tbl_drop_table'

query I
SELECT count(1) FROM [SHOW SCHEDULES]
WHERE label = 'row-level-ttl: $label_suffix'
----
1

statement ok
DROP TABLE tbl_drop_table

query I
SELECT count(1) FROM [SHOW SCHEDULES]
WHERE label = 'row-level-ttl: $label_suffix'
----
0

subtest end

subtest drop_schema

# Create TTL on a different schema and ensure schedules are removed when dropped.
statement ok
CREATE SCHEMA drop_me

statement ok
CREATE TABLE drop_me.tbl () WITH (ttl_expire_after = '10 minutes');
CREATE TABLE drop_me.tbl2 () WITH (ttl_expire_after = '10 minutes')

let $label_suffix
SELECT relname || ' [' || oid || ']' FROM pg_class WHERE relname = 'tbl'

let $label_suffix2
SELECT relname || ' [' || oid || ']' FROM pg_class WHERE relname = 'tbl2'

query I
SELECT count(1) FROM [SHOW SCHEDULES]
WHERE label IN ('row-level-ttl: $label_suffix', 'row-level-ttl: $label_suffix2')
----
2

statement ok
DROP SCHEMA drop_me CASCADE

query I
SELECT count(1) FROM [SHOW SCHEDULES]
WHERE label = 'row-level-ttl: $label_suffix'
----
0

subtest end

subtest drop_database

# Create TTL on a different database and ensure schedules are removed when dropped.
statement ok
CREATE DATABASE drop_me

statement ok
USE drop_me

statement ok
CREATE TABLE tbl () WITH (ttl_expire_after = '10 minutes');
CREATE TABLE tbl2 () WITH (ttl_expire_after = '10 minutes')

let $label_suffix
SELECT relname || ' [' || oid || ']' FROM pg_class WHERE relname = 'tbl'

let $label_suffix2
SELECT relname || ' [' || oid || ']' FROM pg_class WHERE relname = 'tbl2'

query I
SELECT count(1) FROM [SHOW SCHEDULES]
WHERE label IN ('row-level-ttl: $label_suffix', 'row-level-ttl: $label_suffix2')
----
2

statement ok
USE test;

statement ok
DROP DATABASE drop_me CASCADE

query I
SELECT count(1) FROM [SHOW SCHEDULES]
WHERE label = 'row-level-ttl: $label_suffix'
----
0

subtest end

subtest crdb_internal_expiration_invalid_type

statement error table crdb_internal_expiration has TTL defined, but column crdb_internal_expiration is not a TIMESTAMPTZ
CREATE TABLE tbl (
  id INT PRIMARY KEY,
  crdb_internal_expiration INTERVAL
) WITH (ttl_expire_after = '10 minutes')

subtest end

subtest ttl_on_noop

statement ok
CREATE TABLE tbl_ttl_on_noop (
  id INT PRIMARY KEY
) WITH (ttl_expire_after = '10 minutes')

query T
SELECT create_statement FROM [SHOW CREATE TABLE tbl_ttl_on_noop]
----
CREATE TABLE public.tbl_ttl_on_noop (
  id INT8 NOT NULL,
  crdb_internal_expiration TIMESTAMPTZ NOT VISIBLE NOT NULL DEFAULT current_timestamp():::TIMESTAMPTZ + '00:10:00':::INTERVAL ON UPDATE current_timestamp():::TIMESTAMPTZ + '00:10:00':::INTERVAL,
  CONSTRAINT tbl_ttl_on_noop_pkey PRIMARY KEY (id ASC)
) WITH (ttl = 'on', ttl_expire_after = '00:10:00':::INTERVAL)

# Test no-ops.
statement ok
ALTER TABLE tbl_ttl_on_noop SET (ttl = 'on')

query T
SELECT create_statement FROM [SHOW CREATE TABLE tbl_ttl_on_noop]
----
CREATE TABLE public.tbl_ttl_on_noop (
  id INT8 NOT NULL,
  crdb_internal_expiration TIMESTAMPTZ NOT VISIBLE NOT NULL DEFAULT current_timestamp():::TIMESTAMPTZ + '00:10:00':::INTERVAL ON UPDATE current_timestamp():::TIMESTAMPTZ + '00:10:00':::INTERVAL,
  CONSTRAINT tbl_ttl_on_noop_pkey PRIMARY KEY (id ASC)
) WITH (ttl = 'on', ttl_expire_after = '00:10:00':::INTERVAL)

let $label_suffix
SELECT relname || ' [' || oid || ']' FROM pg_class WHERE relname = 'tbl_ttl_on_noop'

query TTT
SELECT schedule_status, recurrence, owner FROM [SHOW SCHEDULES]
WHERE label = 'row-level-ttl: $label_suffix'
----
ACTIVE  @daily  root

let $schedule_id
SELECT id FROM [SHOW SCHEDULES]
WHERE label = 'row-level-ttl: $label_suffix'

query T
SELECT create_statement FROM [SHOW CREATE SCHEDULE $schedule_id]
----
ALTER TABLE test.public.tbl_ttl_on_noop WITH (ttl = 'on', ...)

subtest end

subtest ttl_job_cron_invalid

statement error invalid cron expression for "ttl_job_cron"
CREATE TABLE tbl () WITH (ttl_expire_after = '10 seconds', ttl_job_cron = 'bad expr')

subtest end

subtest create_ttl_job_cron

statement ok
CREATE TABLE tbl_create_ttl_job_cron (
  id INT PRIMARY KEY
) WITH (ttl_expire_after = '10 minutes', ttl_job_cron = '@daily')

query T
SELECT create_statement FROM [SHOW CREATE TABLE tbl_create_ttl_job_cron]
----
CREATE TABLE public.tbl_create_ttl_job_cron (
  id INT8 NOT NULL,
  crdb_internal_expiration TIMESTAMPTZ NOT VISIBLE NOT NULL DEFAULT current_timestamp():::TIMESTAMPTZ + '00:10:00':::INTERVAL ON UPDATE current_timestamp():::TIMESTAMPTZ + '00:10:00':::INTERVAL,
  CONSTRAINT tbl_create_ttl_job_cron_pkey PRIMARY KEY (id ASC)
) WITH (ttl = 'on', ttl_expire_after = '00:10:00':::INTERVAL, ttl_job_cron = '@daily')

let $label_suffix
SELECT relname || ' [' || oid || ']' FROM pg_class WHERE relname = 'tbl_create_ttl_job_cron'

query TTT
SELECT schedule_status, recurrence, owner FROM [SHOW SCHEDULES]
WHERE label = 'row-level-ttl: $label_suffix'
----
ACTIVE  @daily  root

subtest end

subtest set_ttl_job_cron

statement ok
CREATE TABLE tbl_set_ttl_job_cron (
  id INT PRIMARY KEY
) WITH (ttl_expire_after = '10 minutes', ttl_job_cron = '@daily')

statement ok
ALTER TABLE tbl_set_ttl_job_cron SET (ttl_job_cron = '@weekly')

query T
SELECT create_statement FROM [SHOW CREATE TABLE tbl_set_ttl_job_cron]
----
CREATE TABLE public.tbl_set_ttl_job_cron (
  id INT8 NOT NULL,
  crdb_internal_expiration TIMESTAMPTZ NOT VISIBLE NOT NULL DEFAULT current_timestamp():::TIMESTAMPTZ + '00:10:00':::INTERVAL ON UPDATE current_timestamp():::TIMESTAMPTZ + '00:10:00':::INTERVAL,
  CONSTRAINT tbl_set_ttl_job_cron_pkey PRIMARY KEY (id ASC)
) WITH (ttl = 'on', ttl_expire_after = '00:10:00':::INTERVAL, ttl_job_cron = '@weekly')

let $label_suffix
SELECT relname || ' [' || oid || ']' FROM pg_class WHERE relname = 'tbl_set_ttl_job_cron'

query TTT
SELECT schedule_status, recurrence, owner FROM [SHOW SCHEDULES]
WHERE label = 'row-level-ttl: $label_suffix'
----
ACTIVE  @weekly  root

subtest end

subtest reset_ttl_job_cron

statement ok
CREATE TABLE tbl_reset_ttl_job_cron (
  id INT PRIMARY KEY
) WITH (ttl_expire_after = '10 minutes', ttl_job_cron = '@daily')

statement ok
ALTER TABLE tbl_reset_ttl_job_cron RESET (ttl_job_cron)

query T
SELECT create_statement FROM [SHOW CREATE TABLE tbl_reset_ttl_job_cron]
----
CREATE TABLE public.tbl_reset_ttl_job_cron (
  id INT8 NOT NULL,
  crdb_internal_expiration TIMESTAMPTZ NOT VISIBLE NOT NULL DEFAULT current_timestamp():::TIMESTAMPTZ + '00:10:00':::INTERVAL ON UPDATE current_timestamp():::TIMESTAMPTZ + '00:10:00':::INTERVAL,
  CONSTRAINT tbl_reset_ttl_job_cron_pkey PRIMARY KEY (id ASC)
) WITH (ttl = 'on', ttl_expire_after = '00:10:00':::INTERVAL)

let $label_suffix
SELECT relname || ' [' || oid || ']' FROM pg_class WHERE relname = 'tbl_reset_ttl_job_cron'

query TTT
SELECT schedule_status, recurrence, owner FROM [SHOW SCHEDULES]
WHERE label = 'row-level-ttl: $label_suffix'
----
ACTIVE  @daily  root

subtest end

subtest ttl_must_be_set

statement ok
CREATE TABLE no_ttl_table ()

statement error "ttl_expire_after" and/or "ttl_expiration_expression" must be set
ALTER TABLE no_ttl_table SET (ttl_select_batch_size = 50)

statement error "ttl_expire_after" and/or "ttl_expiration_expression" must be set
ALTER TABLE no_ttl_table SET (ttl_delete_batch_size = 50)

statement error "ttl_expire_after" and/or "ttl_expiration_expression" must be set
ALTER TABLE no_ttl_table SET (ttl_job_cron = '@weekly')

statement error "ttl_expire_after" and/or "ttl_expiration_expression" must be set
ALTER TABLE no_ttl_table SET (ttl_pause = true)

statement error "ttl_expire_after" and/or "ttl_expiration_expression" must be set
ALTER TABLE no_ttl_table SET (ttl_label_metrics = true)

subtest end

subtest ttl_params_positive

statement ok
CREATE TABLE tbl_ttl_params_positive (
  id INT PRIMARY KEY
) WITH (ttl_expire_after = '10 minutes')

statement error "ttl_select_batch_size" must be at least 1
ALTER TABLE tbl_ttl_params_positive SET (ttl_select_batch_size = -1)

statement error "ttl_delete_batch_size" must be at least 1
ALTER TABLE tbl_ttl_params_positive SET (ttl_delete_batch_size = -1)

statement error "ttl_select_rate_limit" must be at least 1
ALTER TABLE tbl_ttl_params_positive SET (ttl_select_rate_limit = -1)

statement error "ttl_delete_rate_limit" must be at least 1
ALTER TABLE tbl_ttl_params_positive SET (ttl_delete_rate_limit = -1)

statement error "ttl_row_stats_poll_interval" must be at least 1
ALTER TABLE tbl_ttl_params_positive SET (ttl_row_stats_poll_interval = '-1 second')

subtest end

subtest set_ttl_params

statement ok
CREATE TABLE tbl_set_ttl_params (
  id INT PRIMARY KEY
) WITH (
  ttl_expire_after = '10 minutes',
  ttl_select_batch_size = 10,
  ttl_delete_batch_size = 20,
  ttl_select_rate_limit = 30,
  ttl_delete_rate_limit = 40,
  ttl_pause = true,
  ttl_row_stats_poll_interval = '1 minute',
  ttl_label_metrics = true,
  ttl_disable_changefeed_replication = true
)

query T
SELECT create_statement FROM [SHOW CREATE TABLE tbl_set_ttl_params]
----
CREATE TABLE public.tbl_set_ttl_params (
  id INT8 NOT NULL,
  crdb_internal_expiration TIMESTAMPTZ NOT VISIBLE NOT NULL DEFAULT current_timestamp():::TIMESTAMPTZ + '00:10:00':::INTERVAL ON UPDATE current_timestamp():::TIMESTAMPTZ + '00:10:00':::INTERVAL,
  CONSTRAINT tbl_set_ttl_params_pkey PRIMARY KEY (id ASC)
) WITH (ttl = 'on', ttl_expire_after = '00:10:00':::INTERVAL, ttl_select_batch_size = 10, ttl_delete_batch_size = 20, ttl_select_rate_limit = 30, ttl_delete_rate_limit = 40, ttl_pause = true, ttl_row_stats_poll_interval = '1m0s', ttl_label_metrics = true, ttl_disable_changefeed_replication = true)

statement ok
ALTER TABLE tbl_set_ttl_params SET (ttl_select_batch_size = 110, ttl_delete_batch_size = 120, ttl_select_rate_limit = 130, ttl_delete_rate_limit = 140, ttl_row_stats_poll_interval = '2m0s')

query T
SELECT create_statement FROM [SHOW CREATE TABLE tbl_set_ttl_params]
----
CREATE TABLE public.tbl_set_ttl_params (
  id INT8 NOT NULL,
  crdb_internal_expiration TIMESTAMPTZ NOT VISIBLE NOT NULL DEFAULT current_timestamp():::TIMESTAMPTZ + '00:10:00':::INTERVAL ON UPDATE current_timestamp():::TIMESTAMPTZ + '00:10:00':::INTERVAL,
  CONSTRAINT tbl_set_ttl_params_pkey PRIMARY KEY (id ASC)
) WITH (ttl = 'on', ttl_expire_after = '00:10:00':::INTERVAL, ttl_select_batch_size = 110, ttl_delete_batch_size = 120, ttl_select_rate_limit = 130, ttl_delete_rate_limit = 140, ttl_pause = true, ttl_row_stats_poll_interval = '2m0s', ttl_label_metrics = true, ttl_disable_changefeed_replication = true)

statement ok
ALTER TABLE tbl_set_ttl_params RESET (
  ttl_select_batch_size,
  ttl_delete_batch_size,
  ttl_select_rate_limit,
  ttl_delete_rate_limit,
  ttl_pause,
  ttl_row_stats_poll_interval,
  ttl_label_metrics,
  ttl_disable_changefeed_replication
)

query T
SELECT create_statement FROM [SHOW CREATE TABLE tbl_set_ttl_params]
----
CREATE TABLE public.tbl_set_ttl_params (
  id INT8 NOT NULL,
  crdb_internal_expiration TIMESTAMPTZ NOT VISIBLE NOT NULL DEFAULT current_timestamp():::TIMESTAMPTZ + '00:10:00':::INTERVAL ON UPDATE current_timestamp():::TIMESTAMPTZ + '00:10:00':::INTERVAL,
  CONSTRAINT tbl_set_ttl_params_pkey PRIMARY KEY (id ASC)
) WITH (ttl = 'on', ttl_expire_after = '00:10:00':::INTERVAL)

subtest end

subtest create_table_ttl_expiration_expression

statement ok
CREATE TABLE tbl_create_table_ttl_expiration_expression (
  id INT PRIMARY KEY,
  expire_at TIMESTAMPTZ,
  FAMILY (id, expire_at)
) WITH (ttl_expiration_expression = 'expire_at')

query T
SELECT create_statement FROM [SHOW CREATE TABLE tbl_create_table_ttl_expiration_expression]
----
CREATE TABLE public.tbl_create_table_ttl_expiration_expression (
  id INT8 NOT NULL,
  expire_at TIMESTAMPTZ NULL,
  CONSTRAINT tbl_create_table_ttl_expiration_expression_pkey PRIMARY KEY (id ASC),
  FAMILY fam_0_id_expire_at (id, expire_at)
) WITH (ttl = 'on', ttl_expiration_expression = 'expire_at')

statement ok
ALTER TABLE tbl_create_table_ttl_expiration_expression RESET (ttl)

query T
SELECT create_statement FROM [SHOW CREATE TABLE tbl_create_table_ttl_expiration_expression]
----
CREATE TABLE public.tbl_create_table_ttl_expiration_expression (
  id INT8 NOT NULL,
  expire_at TIMESTAMPTZ NULL,
  CONSTRAINT tbl_create_table_ttl_expiration_expression_pkey PRIMARY KEY (id ASC),
  FAMILY fam_0_id_expire_at (id, expire_at)
)

subtest end

subtest create_table_ttl_expiration_expression_escape_sql

statement ok
CREATE TABLE tbl_create_table_ttl_expiration_expression_escape_sql (
  id INT PRIMARY KEY,
  expire_at TIMESTAMPTZ,
  FAMILY (id, expire_at)
) WITH (ttl_expiration_expression = 'IF(expire_at > parse_timestamp(''2020-01-01 00:00:00'') AT TIME ZONE ''UTC'', expire_at, NULL)')

query T
SELECT create_statement FROM [SHOW CREATE TABLE tbl_create_table_ttl_expiration_expression_escape_sql]
----
CREATE TABLE public.tbl_create_table_ttl_expiration_expression_escape_sql (
  id INT8 NOT NULL,
  expire_at TIMESTAMPTZ NULL,
  CONSTRAINT tbl_create_table_ttl_expiration_expression_escape_sql_pkey PRIMARY KEY (id ASC),
  FAMILY fam_0_id_expire_at (id, expire_at)
) WITH (ttl = 'on', ttl_expiration_expression = e'IF(expire_at > parse_timestamp(\'2020-01-01 00:00:00\') AT TIME ZONE \'UTC\', expire_at, NULL)')

subtest end

subtest alter_table_ttl_expiration_expression

statement ok
CREATE TABLE tbl_alter_table_ttl_expiration_expression (
  id INT PRIMARY KEY,
  expire_at TIMESTAMPTZ,
  FAMILY (id, expire_at)
)

statement error expected TTL EXPIRATION EXPRESSION expression to have type timestamptz, but 'id' has type int
ALTER TABLE tbl_alter_table_ttl_expiration_expression SET (ttl_expiration_expression = 'id')

statement ok
ALTER TABLE tbl_alter_table_ttl_expiration_expression SET (ttl_expiration_expression = 'expire_at')

# Tested below anyway, so we can skip this statement for legacy schema changer.
skipif config local-legacy-schema-changer
statement error cannot drop column "expire_at" referenced by row-level TTL expiration expression "expire_at"
ALTER TABLE tbl_alter_table_ttl_expiration_expression DROP COLUMN expire_at

statement ok
SET use_declarative_schema_changer = 'off'

statement error cannot drop column "expire_at" referenced by row-level TTL expiration expression "expire_at"\nHINT: use ALTER TABLE .*
ALTER TABLE tbl_alter_table_ttl_expiration_expression DROP COLUMN expire_at

statement ok
SET use_declarative_schema_changer = 'on'

statement error cannot alter type of column "expire_at" referenced by row-level TTL expiration expression "expire_at"\nHINT: use ALTER TABLE .*
ALTER TABLE tbl_alter_table_ttl_expiration_expression ALTER expire_at TYPE TIMESTAMP USING (expire_at AT TIME ZONE 'UTC')

query T
SELECT create_statement FROM [SHOW CREATE TABLE tbl_alter_table_ttl_expiration_expression]
----
CREATE TABLE public.tbl_alter_table_ttl_expiration_expression (
  id INT8 NOT NULL,
  expire_at TIMESTAMPTZ NULL,
  CONSTRAINT tbl_alter_table_ttl_expiration_expression_pkey PRIMARY KEY (id ASC),
  FAMILY fam_0_id_expire_at (id, expire_at)
) WITH (ttl = 'on', ttl_expiration_expression = 'expire_at')

# try setting it again
statement ok
ALTER TABLE tbl_alter_table_ttl_expiration_expression SET (ttl_expiration_expression = '((expire_at AT TIME ZONE ''UTC'') + ''5 minutes'':::INTERVAL) AT TIME ZONE ''UTC''')

query T
SELECT create_statement FROM [SHOW CREATE TABLE tbl_alter_table_ttl_expiration_expression]
----
CREATE TABLE public.tbl_alter_table_ttl_expiration_expression (
  id INT8 NOT NULL,
  expire_at TIMESTAMPTZ NULL,
  CONSTRAINT tbl_alter_table_ttl_expiration_expression_pkey PRIMARY KEY (id ASC),
  FAMILY fam_0_id_expire_at (id, expire_at)
) WITH (ttl = 'on', ttl_expiration_expression = e'((expire_at AT TIME ZONE \'UTC\') + \'5 minutes\':::INTERVAL) AT TIME ZONE \'UTC\'')

statement ok
ALTER TABLE tbl_alter_table_ttl_expiration_expression RESET (ttl)

query T
SELECT create_statement FROM [SHOW CREATE TABLE tbl_alter_table_ttl_expiration_expression]
----
CREATE TABLE public.tbl_alter_table_ttl_expiration_expression (
  id INT8 NOT NULL,
  expire_at TIMESTAMPTZ NULL,
  CONSTRAINT tbl_alter_table_ttl_expiration_expression_pkey PRIMARY KEY (id ASC),
  FAMILY fam_0_id_expire_at (id, expire_at)
)

subtest end

subtest add_ttl_expiration_expression_to_ttl_expire_after

statement ok
CREATE TABLE tbl_add_ttl_expiration_expression_to_ttl_expire_after (
  id INT PRIMARY KEY,
  expire_at TIMESTAMPTZ,
  FAMILY (id, expire_at)
) WITH (ttl_expire_after = '10 minutes')

statement ok
ALTER TABLE tbl_add_ttl_expiration_expression_to_ttl_expire_after SET (ttl_expiration_expression = 'crdb_internal_expiration')

query T
SELECT create_statement FROM [SHOW CREATE TABLE tbl_add_ttl_expiration_expression_to_ttl_expire_after]
----
CREATE TABLE public.tbl_add_ttl_expiration_expression_to_ttl_expire_after (
  id INT8 NOT NULL,
  expire_at TIMESTAMPTZ NULL,
  crdb_internal_expiration TIMESTAMPTZ NOT VISIBLE NOT NULL DEFAULT current_timestamp():::TIMESTAMPTZ + '00:10:00':::INTERVAL ON UPDATE current_timestamp():::TIMESTAMPTZ + '00:10:00':::INTERVAL,
  CONSTRAINT tbl_add_ttl_expiration_expression_to_ttl_expire_after_pkey PRIMARY KEY (id ASC),
  FAMILY fam_0_id_expire_at_crdb_internal_expiration (id, expire_at, crdb_internal_expiration)
) WITH (ttl = 'on', ttl_expire_after = '00:10:00':::INTERVAL, ttl_expiration_expression = 'crdb_internal_expiration')

let $label_suffix
SELECT relname || ' [' || oid || ']' FROM pg_class WHERE relname = 'tbl_add_ttl_expiration_expression_to_ttl_expire_after'

query TTT
SELECT schedule_status, recurrence, owner FROM [SHOW SCHEDULES]
WHERE label = 'row-level-ttl: $label_suffix'
----
ACTIVE  @daily  root

subtest end

subtest add_ttl_expire_after_to_ttl_expiration_expression

statement ok
CREATE TABLE tbl_add_ttl_expire_after_to_ttl_expiration_expression (
  id INT PRIMARY KEY,
  expire_at TIMESTAMPTZ,
  FAMILY (id, expire_at)
) WITH (ttl_expiration_expression = 'expire_at')

statement ok
ALTER TABLE tbl_add_ttl_expire_after_to_ttl_expiration_expression SET (ttl_expire_after = '10 minutes')

query T
SELECT create_statement FROM [SHOW CREATE TABLE tbl_add_ttl_expire_after_to_ttl_expiration_expression]
----
CREATE TABLE public.tbl_add_ttl_expire_after_to_ttl_expiration_expression (
  id INT8 NOT NULL,
  expire_at TIMESTAMPTZ NULL,
  crdb_internal_expiration TIMESTAMPTZ NOT VISIBLE NOT NULL DEFAULT current_timestamp():::TIMESTAMPTZ + '00:10:00':::INTERVAL ON UPDATE current_timestamp():::TIMESTAMPTZ + '00:10:00':::INTERVAL,
  CONSTRAINT tbl_add_ttl_expire_after_to_ttl_expiration_expression_pkey PRIMARY KEY (id ASC),
  FAMILY fam_0_id_expire_at (id, expire_at, crdb_internal_expiration)
) WITH (ttl = 'on', ttl_expire_after = '00:10:00':::INTERVAL, ttl_expiration_expression = 'expire_at')

let $label_suffix
SELECT relname || ' [' || oid || ']' FROM pg_class WHERE relname = 'tbl_add_ttl_expire_after_to_ttl_expiration_expression'

query TTT
SELECT schedule_status, recurrence, owner FROM [SHOW SCHEDULES]
WHERE label = 'row-level-ttl: $label_suffix'
----
ACTIVE  @daily  root

subtest end

subtest create_table_ttl_expire_after_and_ttl_expiration_expression

statement ok
CREATE TABLE create_table_ttl_expire_after_and_ttl_expiration_expression (
  id INT PRIMARY KEY
) WITH (ttl_expire_after = '10 minutes', ttl_expiration_expression = 'crdb_internal_expiration')

query T
SELECT create_statement FROM [SHOW CREATE TABLE create_table_ttl_expire_after_and_ttl_expiration_expression]
----
CREATE TABLE public.create_table_ttl_expire_after_and_ttl_expiration_expression (
  id INT8 NOT NULL,
  crdb_internal_expiration TIMESTAMPTZ NOT VISIBLE NOT NULL DEFAULT current_timestamp():::TIMESTAMPTZ + '00:10:00':::INTERVAL ON UPDATE current_timestamp():::TIMESTAMPTZ + '00:10:00':::INTERVAL,
  CONSTRAINT create_table_ttl_expire_after_and_ttl_expiration_expression_pkey PRIMARY KEY (id ASC)
) WITH (ttl = 'on', ttl_expire_after = '00:10:00':::INTERVAL, ttl_expiration_expression = 'crdb_internal_expiration')

statement ok
ALTER TABLE create_table_ttl_expire_after_and_ttl_expiration_expression RESET (ttl)

query T
SELECT create_statement FROM [SHOW CREATE TABLE create_table_ttl_expire_after_and_ttl_expiration_expression]
----
CREATE TABLE public.create_table_ttl_expire_after_and_ttl_expiration_expression (
  id INT8 NOT NULL,
  CONSTRAINT create_table_ttl_expire_after_and_ttl_expiration_expression_pkey PRIMARY KEY (id ASC)
)

subtest end

subtest alter_table_ttl_expire_after_and_ttl_expiration_expression

statement ok
CREATE TABLE tbl_alter_table_ttl_expire_after_and_ttl_expiration_expression (
  id INT PRIMARY KEY
)

statement ok
ALTER TABLE tbl_alter_table_ttl_expire_after_and_ttl_expiration_expression SET (ttl_expire_after = '10 minutes', ttl_expiration_expression = 'crdb_internal_expiration')

query T
SELECT create_statement FROM [SHOW CREATE TABLE tbl_alter_table_ttl_expire_after_and_ttl_expiration_expression]
----
CREATE TABLE public.tbl_alter_table_ttl_expire_after_and_ttl_expiration_expression (
  id INT8 NOT NULL,
  crdb_internal_expiration TIMESTAMPTZ NOT VISIBLE NOT NULL DEFAULT current_timestamp():::TIMESTAMPTZ + '00:10:00':::INTERVAL ON UPDATE current_timestamp():::TIMESTAMPTZ + '00:10:00':::INTERVAL,
  CONSTRAINT tbl_alter_table_ttl_expire_after_and_ttl_expiration_expression_pkey PRIMARY KEY (id ASC)
) WITH (ttl = 'on', ttl_expire_after = '00:10:00':::INTERVAL, ttl_expiration_expression = 'crdb_internal_expiration')

statement ok
ALTER TABLE tbl_alter_table_ttl_expire_after_and_ttl_expiration_expression RESET (ttl)

query T
SELECT create_statement FROM [SHOW CREATE TABLE tbl_alter_table_ttl_expire_after_and_ttl_expiration_expression]
----
CREATE TABLE public.tbl_alter_table_ttl_expire_after_and_ttl_expiration_expression (
  id INT8 NOT NULL,
  CONSTRAINT tbl_alter_table_ttl_expire_after_and_ttl_expiration_expression_pkey PRIMARY KEY (id ASC)
)

subtest end

subtest ttl_expiration_expression_rename

statement ok
CREATE TABLE tbl_ttl_expiration_expression_renamed (
  id INT PRIMARY KEY,
  expires_at TIMESTAMPTZ,
  FAMILY fam (id, expires_at)
) WITH (ttl_expiration_expression = 'expires_at')

statement ok
ALTER TABLE tbl_ttl_expiration_expression_renamed RENAME expires_at TO expires_at_renamed

query T
SELECT create_statement FROM [SHOW CREATE TABLE tbl_ttl_expiration_expression_renamed]
----
CREATE TABLE public.tbl_ttl_expiration_expression_renamed (
  id INT8 NOT NULL,
  expires_at_renamed TIMESTAMPTZ NULL,
  CONSTRAINT tbl_ttl_expiration_expression_renamed_pkey PRIMARY KEY (id ASC),
  FAMILY fam (id, expires_at_renamed)
) WITH (ttl = 'on', ttl_expiration_expression = 'expires_at_renamed')

subtest end

subtest crdb_internal_expiration_already_defined

statement ok
CREATE TABLE tbl_crdb_internal_expiration_already_defined (
  id INT PRIMARY KEY,
  crdb_internal_expiration TIMESTAMPTZ
)

statement error cannot add TTL to table with the crdb_internal_expiration column already defined
ALTER TABLE tbl_crdb_internal_expiration_already_defined SET (ttl_expire_after = '10 minutes')

subtest end

subtest desc_pk_with_ttl

statement ok
CREATE TABLE tbl_desc_pk_with_ttl (id INT, id2 INT, PRIMARY KEY (id, id2 DESC)) WITH (ttl_expire_after = '10 minutes')

subtest end

subtest desc_pk_without_ttl_add_ttl

statement ok
CREATE TABLE tbl_desc_pk_without_ttl_add_ttl (id INT, id2 INT, PRIMARY KEY (id, id2 DESC))

statement ok
ALTER TABLE tbl_desc_pk_without_ttl_add_ttl SET (ttl_expire_after = '10 minutes')

subtest end

subtest asc_pk_alter_desc_pk

statement ok
CREATE TABLE tbl_asc_pk_alter_desc_pk (id INT, id2 INT, PRIMARY KEY (id, id2)) WITH (ttl_expire_after = '10 minutes')

statement ok
ALTER TABLE tbl_asc_pk_alter_desc_pk ALTER PRIMARY KEY USING COLUMNS (id, id2 DESC)

subtest end

subtest create_table_no_ttl_set_ttl_expire_after

statement ok
CREATE TABLE create_table_no_ttl_set_ttl_expire_after (
   id INT PRIMARY KEY
)

statement ok
ALTER TABLE create_table_no_ttl_set_ttl_expire_after SET (ttl_expire_after = '10 minutes')

query T
SELECT create_statement FROM [SHOW CREATE TABLE create_table_no_ttl_set_ttl_expire_after]
----
CREATE TABLE public.create_table_no_ttl_set_ttl_expire_after (
  id INT8 NOT NULL,
  crdb_internal_expiration TIMESTAMPTZ NOT VISIBLE NOT NULL DEFAULT current_timestamp():::TIMESTAMPTZ + '00:10:00':::INTERVAL ON UPDATE current_timestamp():::TIMESTAMPTZ + '00:10:00':::INTERVAL,
  CONSTRAINT create_table_no_ttl_set_ttl_expire_after_pkey PRIMARY KEY (id ASC)
) WITH (ttl = 'on', ttl_expire_after = '00:10:00':::INTERVAL)

let $label_suffix
SELECT relname || ' [' || oid || ']' FROM pg_class WHERE relname = 'create_table_no_ttl_set_ttl_expire_after'

query TTT
SELECT schedule_status, recurrence, owner FROM [SHOW SCHEDULES]
WHERE label = 'row-level-ttl: $label_suffix'
----
ACTIVE  @daily  root

statement ok
ALTER TABLE create_table_no_ttl_set_ttl_expire_after RESET (ttl)

query TTT
SELECT schedule_status, recurrence, owner FROM [SHOW SCHEDULES]
WHERE label = 'row-level-ttl: $label_suffix'
----

subtest end

subtest create_table_no_ttl_set_ttl_expiration_expression

statement ok
CREATE TABLE create_table_no_ttl_set_ttl_expiration_expression (
   id INT PRIMARY KEY,
   expire_at TIMESTAMPTZ,
   FAMILY (id, expire_at)
)

statement ok
ALTER TABLE create_table_no_ttl_set_ttl_expiration_expression SET (ttl_expiration_expression = 'expire_at')

query T
SELECT create_statement FROM [SHOW CREATE TABLE create_table_no_ttl_set_ttl_expiration_expression]
----
CREATE TABLE public.create_table_no_ttl_set_ttl_expiration_expression (
  id INT8 NOT NULL,
  expire_at TIMESTAMPTZ NULL,
  CONSTRAINT create_table_no_ttl_set_ttl_expiration_expression_pkey PRIMARY KEY (id ASC),
  FAMILY fam_0_id_expire_at (id, expire_at)
) WITH (ttl = 'on', ttl_expiration_expression = 'expire_at')

let $label_suffix
SELECT relname || ' [' || oid || ']' FROM pg_class WHERE relname = 'create_table_no_ttl_set_ttl_expiration_expression'

query TTT
SELECT schedule_status, recurrence, owner FROM [SHOW SCHEDULES]
WHERE label = 'row-level-ttl: $label_suffix'
----
ACTIVE  @daily  root

statement ok
ALTER TABLE create_table_no_ttl_set_ttl_expiration_expression RESET (ttl)

query TTT
SELECT schedule_status, recurrence, owner FROM [SHOW SCHEDULES]
WHERE label = 'row-level-ttl: $label_suffix'
----

subtest end

subtest special_table_name

statement ok
CREATE TABLE "Table-Name" (id INT PRIMARY KEY) WITH (ttl_expire_after = '10 hours')

let $label_suffix
SELECT relname || ' [' || oid || ']' FROM pg_class WHERE relname = 'Table-Name'

let $schedule_id
SELECT id FROM [SHOW SCHEDULES]
WHERE label = 'row-level-ttl: $label_suffix'

query T
SELECT create_statement FROM [SHOW CREATE SCHEDULE $schedule_id]
----
ALTER TABLE test.public."Table-Name" WITH (ttl = 'on', ...)

statement ok
DROP TABLE "Table-Name"

subtest end

# sets both ttl_exipire_after and ttl_expiration_expression
subtest set_both_reset_ttl_expire_after

statement ok
CREATE TABLE tbl_set_both_reset_ttl_expire_after (
  id INT PRIMARY KEY,
  expire_at TIMESTAMPTZ,
  FAMILY (id, expire_at)
) WITH (
  ttl_expire_after = '10m',
  ttl_expiration_expression = 'expire_at'
)

statement ok
ALTER TABLE tbl_set_both_reset_ttl_expire_after RESET (ttl_expire_after)

query T
SELECT create_statement FROM [SHOW CREATE TABLE tbl_set_both_reset_ttl_expire_after]
----
CREATE TABLE public.tbl_set_both_reset_ttl_expire_after (
  id INT8 NOT NULL,
  expire_at TIMESTAMPTZ NULL,
  CONSTRAINT tbl_set_both_reset_ttl_expire_after_pkey PRIMARY KEY (id ASC),
  FAMILY fam_0_id_expire_at_crdb_internal_expiration (id, expire_at)
) WITH (ttl = 'on', ttl_expiration_expression = 'expire_at')

let $label_suffix
SELECT relname || ' [' || oid || ']' FROM pg_class WHERE relname = 'tbl_set_both_reset_ttl_expire_after'

query TTT
SELECT schedule_status, recurrence, owner FROM [SHOW SCHEDULES]
WHERE label = 'row-level-ttl: $label_suffix'
----
ACTIVE  @daily  root

subtest end

# sets both ttl_exipire_after and ttl_expiration_expression
subtest set_both_reset_ttl_expiration_expression

statement ok
CREATE TABLE tbl_set_both_reset_ttl_expiration_expression (
  id INT PRIMARY KEY,
  expire_at TIMESTAMPTZ,
  FAMILY (id, expire_at)
) WITH (
  ttl_expire_after = '10m',
  ttl_expiration_expression = 'expire_at'
)

statement ok
ALTER TABLE tbl_set_both_reset_ttl_expiration_expression RESET (ttl_expiration_expression)

query T
SELECT create_statement FROM [SHOW CREATE TABLE tbl_set_both_reset_ttl_expiration_expression]
----
CREATE TABLE public.tbl_set_both_reset_ttl_expiration_expression (
  id INT8 NOT NULL,
  expire_at TIMESTAMPTZ NULL,
  crdb_internal_expiration TIMESTAMPTZ NOT VISIBLE NOT NULL DEFAULT current_timestamp():::TIMESTAMPTZ + '00:10:00':::INTERVAL ON UPDATE current_timestamp():::TIMESTAMPTZ + '00:10:00':::INTERVAL,
  CONSTRAINT tbl_set_both_reset_ttl_expiration_expression_pkey PRIMARY KEY (id ASC),
  FAMILY fam_0_id_expire_at_crdb_internal_expiration (id, expire_at, crdb_internal_expiration)
) WITH (ttl = 'on', ttl_expire_after = '00:10:00':::INTERVAL)

let $label_suffix
SELECT relname || ' [' || oid || ']' FROM pg_class WHERE relname = 'tbl_set_both_reset_ttl_expiration_expression'

query TTT
SELECT schedule_status, recurrence, owner FROM [SHOW SCHEDULES]
WHERE label = 'row-level-ttl: $label_suffix'
----
ACTIVE  @daily  root

subtest end

# Subtest set_fk_on_table_with_ttl creates inbound foreign key dependency
# on table with TTL enabled and confirms that a notice regarding implications
# on performance of TTL job deletions is raised as appropriate.
# Weak isolation levels emit extra notices, so skip them for the purpose
# of this subtest.
subtest set_fk_on_table_with_ttl
statement ok
CREATE TABLE tbl_with_ttl (
  id INT PRIMARY KEY,
  expire_at TIMESTAMPTZ,
  FAMILY (id, expire_at)
) WITH (
  ttl_expiration_expression = 'expire_at'
)

skipif config weak-iso-level-configs
query T noticetrace
CREATE TABLE tbl_with_dep(
  id1 INT PRIMARY KEY,
  id INT REFERENCES tbl_with_ttl(id) ON DELETE CASCADE
)
----
NOTICE: Table tbl_with_ttl has row level TTL enabled. This will make TTL deletion jobs more expensive as dependent rows will need to be updated as well. To improve performance of the TTL job, consider reducing the value of ttl_delete_batch_size.

# Create a table with a dependency on tbl_with_ttl but with the default action of no update on delete
# and confirm no notice is raised.
skipif config weak-iso-level-configs
query T noticetrace
CREATE TABLE tbl_with_dep_2(
  id1 INT PRIMARY KEY,
  id INT REFERENCES tbl_with_ttl(id)
)
----

# Alter a table with dependency on tbl_with_ttl and confirm notice is raised.
statement ok
CREATE TABLE tbl_to_alter (
    t_id SERIAL PRIMARY KEY,
    f_id INT NOT NULL,
    name STRING NOT NULL
);

skipif config weak-iso-level-configs
query T noticetrace
ALTER TABLE tbl_to_alter ADD CONSTRAINT fk_tbl_with_ttl FOREIGN KEY(f_id) REFERENCES tbl_with_ttl(id) ON DELETE CASCADE
----
NOTICE: Table tbl_with_ttl has row level TTL enabled. This will make TTL deletion jobs more expensive as dependent rows will need to be updated as well. To improve performance of the TTL job, consider reducing the value of ttl_delete_batch_size.

# Alter a table with dependency on tbl_with_ttl with the default action of
# no updates on deletes and confirm no notice is raised.
statement ok
CREATE TABLE tbl_to_alter_2 (
    t_id SERIAL PRIMARY KEY,
    f_id INT NOT NULL,
    name STRING NOT NULL
);

skipif config weak-iso-level-configs
query T noticetrace
ALTER TABLE tbl_to_alter_2 ADD CONSTRAINT fk_tbl_with_ttl FOREIGN KEY(f_id) REFERENCES tbl_with_ttl(id)
----

# Alter a table with inbound foreign keys to enable row level TTL and confirm
# notice is raised.
statement ok
CREATE TABLE tbl_to_add_ttl(
  id INT PRIMARY KEY,
  expire_at TIMESTAMPTZ NOT NULL DEFAULT now() + '30 days'
)

statement ok
CREATE TABLE tbl_with_fk_default_action(
  id1 INT PRIMARY KEY,
  name STRING,
  id INT REFERENCES tbl_to_add_ttl(id)
)

# Confirm no notice is raised.
skipif config weak-iso-level-configs
query T noticetrace
ALTER TABLE tbl_to_add_ttl SET (ttl_expiration_expression = 'expire_at')
----

statement ok
ALTER TABLE tbl_to_add_ttl RESET (ttl);

statement ok
CREATE TABLE tbl_with_fk(
  id1 INT PRIMARY KEY,
  name STRING,
  id INT REFERENCES tbl_to_add_ttl(id) ON DELETE CASCADE
)

# Confirm notice is raised.
skipif config weak-iso-level-configs
query T noticetrace
ALTER TABLE tbl_to_add_ttl SET (ttl_expiration_expression = 'expire_at')
----
NOTICE: Columns within table tbl_to_add_ttl are referenced as foreign keys. This will make TTL deletion jobs more expensive as dependent rows in other tables will need to be updated as well. To improve performance of the TTL job, consider reducing the value of ttl_delete_batch_size.

subtest end
