# LogicTest: !enterprise-configs

query IBIT colnames
SELECT id, active, length(info), name FROM system.tenants ORDER BY id
----
id  active  length  name
1   true    12      system

# Create three tenants.

query I
SELECT crdb_internal.create_tenant(5)
----
5

# Verify that DROP TENANT is blocked when the service is not NONE.
statement error cannot drop tenant.*in service mode external
DROP TENANT [5]

# create_tenant auto-sets the service for backward-compatibility.
# Reset it here so the tests below don't get confused.
statement ok
ALTER TENANT [5] STOP SERVICE

query error invalid tenant name
SELECT crdb_internal.create_tenant(10, 'ABC')

query error invalid tenant name
SELECT crdb_internal.create_tenant(10, 'invalid_name')

query error invalid tenant name
SELECT crdb_internal.create_tenant(10, 'invalid.name')

# The max tenant ID is less or equal to 18446744073709551614.
query error out of range
SELECT crdb_internal.create_tenant('{"id":18446744073709551615}'::jsonb)

query I
SELECT crdb_internal.create_tenant(10, 'tenant-number-ten')
----
10

query I
SELECT crdb_internal.create_tenant('tenant-number-eleven')
----
11

query IBTIITT colnames
SELECT
  id,
  active,
  name,
  data_state,
  service_mode,
  json_extract_path_text(crdb_internal.pb_to_json('cockroach.multitenant.ProtoInfo', info, true), 'deprecatedDataState') AS deprecated_data_state,
  json_extract_path_text(crdb_internal.pb_to_json('cockroach.multitenant.ProtoInfo', info, true), 'droppedName') AS dropped_name
FROM system.tenants
ORDER BY id
----
id  active  name                  data_state  service_mode  deprecated_data_state  dropped_name
1   true    system                1           2             READY                  ·
5   true    cluster-5              1           0             READY                  ·
10  true    tenant-number-ten     1           0             READY                  ·
11  true    tenant-number-eleven  1           0             READY                  ·

# Check we can add a name where none existed before.
statement ok
ALTER TENANT [5] RENAME TO "my-tenant"

query IBT colnames
SELECT id, active, name FROM system.tenants ORDER BY id
----
id  active  name
1   true    system
5   true    my-tenant
10  true    tenant-number-ten
11  true    tenant-number-eleven


# Check we can change the name when there was one before.
statement ok
ALTER TENANT [5] RENAME TO "my-new-tenant-name"

statement error invalid tenant name
ALTER TENANT [5] RENAME TO 'AAA'

statement error invalid tenant name
ALTER TENANT [5] RENAME TO '-a-'

statement error invalid tenant name
ALTER TENANT [5] RENAME TO '11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111'

statement error invalid tenant name
ALTER TENANT [5] RENAME TO 'invalid_name'

statement error invalid tenant name
ALTER TENANT [5] RENAME TO 'invalid.name'

# Check for duplicate names.
statement error name "tenant-number-ten" is already taken
ALTER TENANT [5] RENAME TO 'tenant-number-ten'

query error tenant with name "tenant-number-eleven" already exists
SELECT crdb_internal.create_tenant('tenant-number-eleven')

query IBT colnames
SELECT id, active, name FROM system.tenants ORDER BY id
----
id  active  name
1   true    system
5   true    my-new-tenant-name
10  true    tenant-number-ten
11  true    tenant-number-eleven

# Note this just marks the tenant as dropped but does not call GC.

statement ok
DROP TENANT [5]

query IBTIITT colnames
SELECT
  id,
  active,
  name,
  data_state,
  service_mode,
  json_extract_path_text(crdb_internal.pb_to_json('cockroach.multitenant.ProtoInfo', info, true), 'deprecatedDataState') AS deprecated_data_state,
  json_extract_path_text(crdb_internal.pb_to_json('cockroach.multitenant.ProtoInfo', info, true), 'droppedName') AS dropped_name
FROM system.tenants
ORDER BY id
----
id  active  name                  data_state  service_mode  deprecated_data_state  dropped_name
1   true    system                1           2             READY                  ·
5   false   NULL                  2           0             DROP                   my-new-tenant-name
10  true    tenant-number-ten     1           0             READY                  ·
11  true    tenant-number-eleven  1           0             READY                  ·


# Try to recreate an existing tenant.
# GC job for tenant 5 has not run yet.
query error pgcode 42710 a tenant with ID 5 or with name "cluster-5" already exists
SELECT crdb_internal.create_tenant(5)

query error pgcode 42710 a tenant with ID 10 or with name "cluster-10" already exists
SELECT crdb_internal.create_tenant(10)

query error pgcode 42710 a tenant with ID 11 or with name "tenant-number-ten" already exists
SELECT crdb_internal.create_tenant(11, 'tenant-number-ten')

# Try to manipulate system.tenants directly as the root user.

statement error pgcode 42501 user root does not have INSERT privilege on relation tenants
INSERT INTO system.tenants VALUES (15)

statement error pgcode 42501 user root does not have INSERT privilege on relation tenants
UPSERT INTO system.tenants VALUES (20)

statement error pgcode 42501 user root does not have UPDATE privilege on relation tenants
UPDATE system.tenants SET active = false WHERE id = 10

statement error pgcode 42501 user root does not have DELETE privilege on relation tenants
DELETE FROM system.tenants WHERE id = 10

# The system tenant cannot be created or destroyed.

query error pgcode 22023 cannot create tenant "1", ID assigned to system tenant
SELECT crdb_internal.create_tenant(1)

statement error pgcode 22023 cannot rename tenant "1", ID assigned to system tenant
ALTER TENANT [1] RENAME TO hello

statement error pgcode 22023 cannot destroy tenant "1", ID assigned to system tenant
DROP TENANT [1]

# Verify that tenants are able to set in-memory cluster settings in logic tests.

statement ok
SET CLUSTER SETTING sql.defaults.vectorize='off'

query T
SHOW CLUSTER SETTING sql.defaults.vectorize
----
off

statement ok
RESET CLUSTER SETTING sql.defaults.vectorize

query T
SHOW CLUSTER SETTING sql.defaults.vectorize
----
on

# Manipulate the tenants zone configurations

query TT
SHOW ZONE CONFIGURATION FOR RANGE tenants
----
RANGE default  ALTER RANGE default CONFIGURE ZONE USING
                 range_min_bytes = 134217728,
                 range_max_bytes = 536870912,
                 gc.ttlseconds = 14400,
                 num_replicas = 3,
                 constraints = '[]',
                 lease_preferences = '[]'

statement ok
ALTER RANGE tenants CONFIGURE ZONE USING gc.ttlseconds = 1

query TT
SHOW ZONE CONFIGURATION FOR RANGE tenants
----
RANGE tenants  ALTER RANGE tenants CONFIGURE ZONE USING
               range_min_bytes = 134217728,
               range_max_bytes = 536870912,
               gc.ttlseconds = 1,
               num_replicas = 3,
               constraints = '[]',
               lease_preferences = '[]'

# Set the jobs adopt interval so that this test doesn't take 30 seconds.
statement ok
SET CLUSTER SETTING jobs.registry.interval.adopt = '1s'

query T
SELECT status FROM [
  SHOW JOB WHEN COMPLETE (
      SELECT job_id FROM crdb_internal.jobs
      WHERE description = 'GC for tenant 5'
  )
]
----
succeeded

statement error pgcode 42704 tenant "5" does not exist
DROP TENANT [5]

query IBTIITT colnames
SELECT
  id,
  active,
  name,
  data_state,
  service_mode,
  json_extract_path_text(crdb_internal.pb_to_json('cockroach.multitenant.ProtoInfo', info, true), 'deprecatedDataState') AS deprecated_data_state,
  json_extract_path_text(crdb_internal.pb_to_json('cockroach.multitenant.ProtoInfo', info, true), 'droppedName') AS dropped_name
FROM system.tenants
ORDER BY id
----
id  active  name                  data_state  service_mode  deprecated_data_state  dropped_name
1   true    system                1           2             READY                  ·
10  true    tenant-number-ten     1           0             READY                  ·
11  true    tenant-number-eleven  1           0             READY                  ·

query error tenant resource limits require a CCL binary
SELECT crdb_internal.update_tenant_resource_limits(10, 1000, 100, 0, now(), 0)

query error tenant resource limits require a CCL binary
SELECT crdb_internal.update_tenant_resource_limits('tenant-number-ten', 1000, 100, 0)

user testuser

statement error user testuser does not have MANAGEVIRTUALCLUSTER system privilege
SELECT crdb_internal.create_tenant(314)

statement error user testuser does not have MANAGEVIRTUALCLUSTER system privilege
SELECT crdb_internal.create_tenant('not-allowed')

statement error user testuser does not have MANAGEVIRTUALCLUSTER system privilege
DROP TENANT [1]

user root

subtest avoid_tenant_id_reuse

# Check what is the last tenant ID assigned according to the tenant ID sequence.
query I
SELECT last_value FROM system.tenant_id_seq
----
11

# Remove the last tenant with IMMEDIATE, which ensures the record is immediately
# removed. Then create another one.
statement ok
DROP TENANT [11] IMMEDIATE;
CREATE TENANT anothertenant

query ITI
SELECT id, name, data_state FROM system.tenants ORDER BY id
----
1   system             1
10  tenant-number-ten  1
12  anothertenant      1

# Check the sequence was updated.
query I
SELECT last_value FROM system.tenant_id_seq
----
12

# Now force a tenant with a large ID, "a la" serverless.
statement ok
SELECT crdb_internal.create_tenant(123)

# Check the sequence was updated.
query I
SELECT last_value FROM system.tenant_id_seq
----
123

# Check that the next tenant created picks up a higher ID.
statement ok
CREATE TENANT yetanotherone

# Check the sequence was updated.
query I
SELECT last_value FROM system.tenant_id_seq
----
124

query ITI
SELECT id, name, data_state FROM system.tenants ORDER BY id
----
1    system             1
10   tenant-number-ten  1
12   anothertenant      1
123  cluster-123         1
124  yetanotherone      1

subtest multiple_tenants_in_txn

statement ok
BEGIN;
SELECT crdb_internal.create_tenant(200);
CREATE TENANT hello;
COMMIT

query ITI
SELECT id, name, data_state FROM system.tenants ORDER BY id
----
1    system             1
10   tenant-number-ten  1
12   anothertenant      1
123  cluster-123         1
124  yetanotherone      1
200  cluster-200         1
201  hello              1

subtest regression_97873

# Verify that destroy_tenant works even in the default service mode,
# for compatibility with CC serverless.
query I
SELECT crdb_internal.create_tenant(97873)
----
97873

query I
SELECT crdb_internal.destroy_tenant(97873)
----
97873

subtest if_not_exists

query error pgcode 42710 a tenant with ID 10 or with name "cluster-10" already exists
SELECT crdb_internal.create_tenant('{"id":10}'::JSONB)

query error pgcode 42710 tenant with name "tenant-number-ten" already exists
SELECT crdb_internal.create_tenant('{"name":"tenant-number-ten"}'::JSONB)

query I
SELECT crdb_internal.create_tenant('{"id":10, "if_not_exists": true}'::JSONB)
----
NULL

query I
SELECT crdb_internal.create_tenant('{"name":"tenant-number-ten", "if_not_exists": true}'::JSONB)
----
NULL

subtest avoid_too_large_ids

query error tenant ID 10000000000 out of range
SELECT crdb_internal.create_tenant(10000000000)
