SDL/declarative (PostgreSQL): CREATE EXTENSION is rejected by the SDL parser but required by the SDL differ, so extension-owned functions get DROP FUNCTION
Summary
In declarative (SDL) mode against PostgreSQL, a database with an installed extension cannot be
managed at all. The two halves of the feature contradict each other:
Export Schema emits CREATE EXTENSION, but the SDL parser rejects it. The exported schema
is not round-trip-clean — feed Bytebase's own export back in as an SDL file and check fails.
- Remove the
CREATE EXTENSION statement and the differ then treats the extension's functions as
orphans, generating DROP FUNCTION for each. PostgreSQL refuses, because extension-owned
functions cannot be dropped individually.
There is no third configuration. Declaring the extension fails validation; not declaring it produces
DDL PostgreSQL will not execute.
Environment
|
|
| Bytebase |
3.21.0 (self-hosted, Docker), commit a9294ccea1a69d49e7ccf31c3cd21415d6152544 |
| Action |
bytebase/bytebase-action:3.21.0, check and rollout with --declarative |
| Target |
PostgreSQL 16 |
| Extension |
pgcrypto (installed into public) |
Reproduction
-
A PostgreSQL database with pgcrypto installed: CREATE EXTENSION IF NOT EXISTS pgcrypto;
-
In Bytebase, Export Schema for that database. The output contains:
CREATE EXTENSION IF NOT EXISTS "pgcrypto" WITH SCHEMA "public" VERSION '1.3';
COMMENT ON EXTENSION "pgcrypto" IS 'cryptographic functions';
-
Use that exported file as the SDL file and run:
bytebase-action check --declarative --file-pattern="schemas/*.sql" \
--targets instances/<inst>/databases/<db> --check-release=FAIL_ON_ERROR
Result — case A:
{
"code": 239,
"ruleType": "PARSER_BASED",
"status": "ERROR",
"title": "Disallowed statement in SDL file",
"content": "Statement type 'CREATE_EXTENSION' is not allowed in SDL files.\n\nSDL files should only contain CREATE and COMMENT statements to declare the desired schema."
}
-
Remove the CREATE EXTENSION and COMMENT ON EXTENSION lines (and, in a further attempt, every
other reference to public). check now passes. Run bytebase-action rollout --declarative ...
against an empty database that has pgcrypto installed.
Result — case B, task fails during Command Execute:
ERROR: cannot drop function armor(bytea) because extension pgcrypto requires it (SQLSTATE 2BP01)
The transaction rolls back, so nothing is damaged — but the rollout can never succeed.
Removing COMMENT ON SCHEMA "public" as well does not help: the differ compares against the whole
database, not only the schemas named in the SDL file, so the extension's functions are still seen
as undeclared objects to drop.
Expected behaviour
Either:
- the differ excludes extension-owned objects — they are identifiable via
pg_depend
(deptype = 'e'), which is the conventional approach and what pgschema does; or
- SDL accepts
CREATE EXTENSION as a declarable object, so the differ knows the extension is
desired and leaves its objects alone.
The first seems more consistent with SDL only permitting CREATE/COMMENT. Either way, Export Schema output should be valid as an SDL file — currently it is not, for any database with an
extension.
Actual behaviour
Declarative mode is unusable on any PostgreSQL database with an installed extension. Since pgcrypto
and uuid-ossp are extremely common, this likely affects many real schemas.
Notes
SDL/declarative (PostgreSQL):
CREATE EXTENSIONis rejected by the SDL parser but required by the SDL differ, so extension-owned functions getDROP FUNCTIONSummary
In declarative (SDL) mode against PostgreSQL, a database with an installed extension cannot be
managed at all. The two halves of the feature contradict each other:
Export SchemaemitsCREATE EXTENSION, but the SDL parser rejects it. The exported schemais not round-trip-clean — feed Bytebase's own export back in as an SDL file and
checkfails.CREATE EXTENSIONstatement and the differ then treats the extension's functions asorphans, generating
DROP FUNCTIONfor each. PostgreSQL refuses, because extension-ownedfunctions cannot be dropped individually.
There is no third configuration. Declaring the extension fails validation; not declaring it produces
DDL PostgreSQL will not execute.
Environment
a9294ccea1a69d49e7ccf31c3cd21415d6152544bytebase/bytebase-action:3.21.0,checkandrolloutwith--declarativepgcrypto(installed intopublic)Reproduction
A PostgreSQL database with
pgcryptoinstalled:CREATE EXTENSION IF NOT EXISTS pgcrypto;In Bytebase, Export Schema for that database. The output contains:
Use that exported file as the SDL file and run:
Result — case A:
{ "code": 239, "ruleType": "PARSER_BASED", "status": "ERROR", "title": "Disallowed statement in SDL file", "content": "Statement type 'CREATE_EXTENSION' is not allowed in SDL files.\n\nSDL files should only contain CREATE and COMMENT statements to declare the desired schema." }Remove the
CREATE EXTENSIONandCOMMENT ON EXTENSIONlines (and, in a further attempt, everyother reference to
public).checknow passes. Runbytebase-action rollout --declarative ...against an empty database that has
pgcryptoinstalled.Result — case B, task fails during Command Execute:
The transaction rolls back, so nothing is damaged — but the rollout can never succeed.
Removing
COMMENT ON SCHEMA "public"as well does not help: the differ compares against the wholedatabase, not only the schemas named in the SDL file, so the extension's functions are still seen
as undeclared objects to drop.
Expected behaviour
Either:
pg_depend(
deptype = 'e'), which is the conventional approach and whatpgschemadoes; orCREATE EXTENSIONas a declarable object, so the differ knows the extension isdesired and leaves its objects alone.
The first seems more consistent with SDL only permitting
CREATE/COMMENT. Either way,Export Schemaoutput should be valid as an SDL file — currently it is not, for any database with anextension.
Actual behaviour
Declarative mode is unusable on any PostgreSQL database with an installed extension. Since
pgcryptoand
uuid-osspare extremely common, this likely affects many real schemas.Notes
timescaledb extension") — there the extension's objects are processed unnecessarily; here they are
actively dropped. ERROR: function uuid_generate_v4() does not exist (SQLSTATE 42883) #10513 (
uuid_generate_v4() does not exist) appears to share the root cause ofextension objects not being modelled.