# Test backing up and restoring a database with user defined functions.
new-cluster name=s
----

exec-sql
CREATE DATABASE db1;
----

exec-sql
USE db1;
----

exec-sql
CREATE SCHEMA sc1;
----

exec-sql
CREATE FUNCTION sc1.f1(a INT) RETURNS INT LANGUAGE SQL AS $$
  SELECT a + 1;
$$;
----

exec-sql
CREATE TABLE sc1.t1(a INT PRIMARY KEY, b INT CHECK(sc1.f1(b) > 1));
----

exec-sql
BACKUP DATABASE db1 INTO 'nodelocal://1/test/'
----

query-sql
WITH descs AS (
  SHOW BACKUP LATEST IN 'nodelocal://1/test/'
)
SELECT database_name, parent_schema_name, object_name, object_type, is_full_cluster FROM descs
----
<nil> <nil> db1 database false
db1 <nil> public schema false
db1 <nil> sc1 schema false
db1 sc1 f1 function false
db1 sc1 t1 table false

exec-sql
RESTORE DATABASE db1 FROM LATEST IN 'nodelocal://1/test/' WITH new_db_name = db1_new
----

exec-sql
USE db1_new
----

# Make sure function ids in CHECK constraint are rewritten.
query-sql
SELECT create_statement FROM [SHOW CREATE TABLE sc1.t1]
----
CREATE TABLE sc1.t1 (
	a INT8 NOT NULL,
	b INT8 NULL,
	CONSTRAINT t1_pkey PRIMARY KEY (a ASC),
	CONSTRAINT check_b CHECK (sc1.f1(b) > 1:::INT8)
)

# Make sure that the CHECK constraint still applies correctly
query-sql
INSERT INTO sc1.t1 VALUES (1, 0)
----
pq: failed to satisfy CHECK constraint (sc1.f1(b) > 1:::INT8)

# Make sure dependency IDs are rewritten.
# Note that technically this only tests forward-reference IDs in depended-on
# objects are rewritten. But since we have cross-references validation, so this
# also means back-references in UDF descriptor are good.
exec-sql
DROP FUNCTION sc1.f1
----
pq: cannot drop function "f1" because other objects ([db1_new.sc1.t1]) still depend on it

# Test backing up and restoring a full cluster with user defined function.
new-cluster name=s1
----

exec-sql cluster=s1
CREATE DATABASE db1;
----

exec-sql cluster=s1
USE db1;
----

exec-sql cluster=s1
CREATE SCHEMA sc1;
----

exec-sql cluster=s1
CREATE FUNCTION sc1.f1(a INT) RETURNS INT LANGUAGE SQL AS $$
  SELECT a + 1;
$$;
----

exec-sql cluster=s1
CREATE TABLE sc1.t1(a INT PRIMARY KEY, b INT CHECK(sc1.f1(b) > 1));
----

exec-sql
BACKUP INTO 'nodelocal://1/test/'
----

query-sql
WITH descs AS (
  SHOW BACKUP LATEST IN 'nodelocal://1/test/'
)
SELECT
  database_name, parent_schema_name, object_name, object_type, is_full_cluster
FROM
  descs
WHERE
  database_name = 'db1'
----
db1 <nil> public schema true
db1 <nil> sc1 schema true
db1 sc1 f1 function true
db1 sc1 t1 table true

# Start a new cluster with the same IO dir.
new-cluster name=s2 share-io-dir=s1
----

# Restore into the new cluster.
exec-sql cluster=s2
RESTORE FROM LATEST IN 'nodelocal://1/test/'
----

exec-sql
USE db1
----

# Make sure function ids in CHECK constraint are rewritten.
query-sql
SELECT create_statement FROM [SHOW CREATE TABLE sc1.t1]
----
CREATE TABLE sc1.t1 (
	a INT8 NOT NULL,
	b INT8 NULL,
	CONSTRAINT t1_pkey PRIMARY KEY (a ASC),
	CONSTRAINT check_b CHECK (sc1.f1(b) > 1:::INT8)
)

# Make sure that CHECK constraint still applies correctly
query-sql
INSERT INTO sc1.t1 VALUES (1, 0)
----
pq: failed to satisfy CHECK constraint (sc1.f1(b) > 1:::INT8)

# Make sure dependency IDs are rewritten.
# Note that technically this only tests forward-reference IDs in depended-on
# objects are rewritten. But since we have cross-references validation, so this
# also means back-references in UDF descriptor are good.
exec-sql
DROP FUNCTION sc1.f1
----
pq: cannot drop function "f1" because other objects ([db1.sc1.t1]) still depend on it

# Make sure that backup and restore individual tables referencing UDFs able to
# drop check constraints.
new-cluster name=s3
----

exec-sql cluster=s3
CREATE DATABASE db1;
----

exec-sql cluster=s3
CREATE DATABASE db2;
----

exec-sql cluster=s3
CREATE DATABASE db3;
----

exec-sql cluster=s3
USE db1;
----

exec-sql cluster=s3
CREATE SCHEMA sc1;
----

exec-sql cluster=s3
CREATE FUNCTION sc1.f1(a INT) RETURNS INT LANGUAGE SQL AS $$
  SELECT a + 1;
$$;
----

exec-sql cluster=s3
CREATE TABLE sc1.t1(a INT PRIMARY KEY, b INT CHECK(sc1.f1(b) > 1));
----

exec-sql
BACKUP DATABASE db1 INTO 'nodelocal://1/test/'
----

query-sql
WITH descs AS (
  SHOW BACKUP LATEST IN 'nodelocal://1/test/'
)
SELECT database_name, parent_schema_name, object_name, object_type, is_full_cluster FROM descs
----
<nil> <nil> db1 database false
db1 <nil> public schema false
db1 <nil> sc1 schema false
db1 sc1 f1 function false
db1 sc1 t1 table false

exec-sql expect-error-regex=(cannot restore table "t1" without referenced function [0-9]+ \(or "skip_missing_udfs" option\))
RESTORE TABLE sc1.t1 FROM LATEST IN 'nodelocal://1/test/' WITH into_db = 'db2';
----
regex matches error

exec-sql
RESTORE TABLE sc1.t1 FROM LATEST IN 'nodelocal://1/test/' WITH into_db = 'db2', skip_missing_udfs;
----

exec-sql
USE db2
----

# Make sure CHECK constraint is dropped.
query-sql
SELECT create_statement FROM [SHOW CREATE TABLE sc1.t1]
----
CREATE TABLE sc1.t1 (
	a INT8 NOT NULL,
	b INT8 NULL,
	CONSTRAINT t1_pkey PRIMARY KEY (a ASC)
)

exec-sql
USE db1
----

exec-sql
BACKUP TABLE sc1.t1 INTO 'nodelocal://1/test/'
----

query-sql
WITH descs AS (
  SHOW BACKUP LATEST IN 'nodelocal://1/test/'
)
SELECT database_name, parent_schema_name, object_name, object_type, is_full_cluster FROM descs
----
<nil> <nil> db1 database false
db1 <nil> sc1 schema false
db1 sc1 t1 table false

exec-sql expect-error-regex=(cannot restore table "t1" without referenced function [0-9]+ \(or "skip_missing_udfs" option\))
RESTORE TABLE sc1.t1 FROM LATEST IN 'nodelocal://1/test/' WITH into_db = 'db3';
----
regex matches error

exec-sql
RESTORE TABLE sc1.t1 FROM LATEST IN 'nodelocal://1/test/' WITH into_db = 'db3', skip_missing_udfs;
----

exec-sql
USE db3
----

# Make sure CHECK constraint is dropped.
query-sql
SELECT create_statement FROM [SHOW CREATE TABLE sc1.t1]
----
CREATE TABLE sc1.t1 (
	a INT8 NOT NULL,
	b INT8 NULL,
	CONSTRAINT t1_pkey PRIMARY KEY (a ASC)
)
