pista plan¶
Print the DDL that makes the database match the schema files.
Synopsis¶
pista plan [option...] file...
Description¶
pista plan reads the desired schema from the files and the current schema from the database. It prints the DDL that changes the current schema into the desired one. Nothing is applied. pista apply runs the same DDL.
The files together form one schema. A statement that refers to another object, for example an ALTER TABLE or a CREATE INDEX, must come after the CREATE of that object. The CREATE can be in the same file or in an earlier one. See Supported objects.
The output is SQL. It starts with the connection and a count of the objects. After that it contains:
- the pre-SQL,
- the concurrently-pre-SQL,
- the
-- pista:execute-firststatements, - the DDL,
- the
-- pista:executestatements, - one
-- ignored:comment for each object that a-- pista:ignoredirective leaves out, - one
-- skipped:comment for each drop that--allow-dropdoes not allow.
An output with no executable DDL ends with -- No changes.
-- Connected to postgres://postgres@localhost:5432/postgres
-- Plan for schema public (2 tables, 0 views, 0 enums, 0 domains, 0 composite types, 0 sequences)
ALTER TABLE public.users ADD COLUMN email text;
-- skipped: DROP TABLE public.legacy_users;
The connection is read-only, so a -- pista:execute check that writes fails at plan time. --no-read-only opens a read-write connection.
Options¶
The general options apply as well.
Connection¶
-cconnstr,--conn-string=connstr- The PostgreSQL connection string, in either form that libpq accepts. The default is
postgres://postgres@localhost/postgres. The environment variable isPISTA_CONN_STR. -ddbname,--dbname=dbname- The database name. It overrides the one in the connection string. The environment variable is
PISTA_DBNAME. --password=password- The password, kept out of the connection string. The environment variable is
PISTA_PASSWORD. --no-read-only- Open the connection read-write. The environment variable is
PISTA_NO_READ_ONLY.
Scope¶
These options decide what is read on both sides. plan --out records them in the plan file. apply-from reads the database with them.
-nschema,--schemas=schema- The schemas to inspect. This option can be given more than once. A name in the files that has no schema is qualified with the first one. The default is
public. The environment variable isPISTA_SCHEMAS. -mold=new,--schema-map=old=new- Read schema old from the database as new. Files written against new then apply to old. This option can be given more than once. Several pairs can also be separated by
;. --search-path=path- The
search_pathfor the connection. The catalog reports an object that is reachable through thesearch_pathwithout its schema. So this option decides which names are reported without a schema. An empty value qualifies every name. The default ispublic. The environment variable isPISTA_SEARCH_PATH. See Notes. -Ipattern,--include=pattern- Manage only the objects whose name matches the pattern.
*and?are wildcards. A wildcard pattern must match the whole name./re/is a regular expression. It matches anywhere in the name unless it is anchored. The pattern is matched against the name alone, without the schema. This option can be given more than once. The environment variable isPISTA_INCLUDE. -Epattern,--exclude=pattern- Leave out the objects whose name matches the pattern. The patterns are the same as for
--include. This option can be given more than once. The environment variable isPISTA_EXCLUDE. --enable=type- Manage only these object types:
table,view,enum,domain,composite_type,sequence,routine. This option can be given more than once. It takes precedence over--disable. The environment variable isPISTA_ENABLE. --disable=type- Leave out these object types. The values are the same as for
--enable. This option can be given more than once. The environment variable isPISTA_DISABLE. --manage-routine- Manage functions and procedures. This option is off by default. Dropping them still requires
--allow-drop routine. The environment variable isPISTA_MANAGE_ROUTINE. See Routines. --manage-storage-param- Manage the storage parameters of tables and materialized views, that is, the
WITH (...)clause. This option is off by default. Without it, the clause is ignored on both sides. Thesecurity_barrierandsecurity_invokeroptions of a plain view are managed in both cases. The environment variable isPISTA_MANAGE_STORAGE_PARAM. See Storage parameters. --skip-partition-child- Manage a partitioned table without its partitions. An
INHERITSchild is not affected. The environment variable isPISTA_SKIP_PARTITION_CHILD. See Skipping partition children.
Statements¶
These options shape the DDL. plan --out writes the result into the plan file.
--allow-drop=type- Allow dropping these object types:
all,table,view,enum,domain,composite_type,sequence,routine,column,constraint,foreign_key,index,policy,trigger. This option can be given more than once. Without it, no drop is planned. Each drop that is not allowed is written as a-- skipped:comment.constraintcovers CHECK, UNIQUE, PRIMARY KEY and EXCLUSION constraints.foreign_keycovers foreign keys.DROP ATTRIBUTEalso requirescomposite_type. Recreating a view, a routine or a trigger also requires its type. The environment variable isPISTA_ALLOW_DROP. See Controlling drops. --pre-sql=sql- The SQL to write before the DDL. This option cannot be used with
--pre-sql-file. The environment variable isPISTA_PRE_SQL. --pre-sql-file=file- The file whose SQL is written before the DDL. The environment variable is
PISTA_PRE_SQL_FILE. --concurrently-pre-sql=sql- The SQL to write after the pre-SQL when the plan contains a
CONCURRENTLYindex statement, for exampleSET lock_timeout. This option cannot be used with--concurrently-pre-sql-file. The environment variable isPISTA_CONCURRENTLY_PRE_SQL. --concurrently-pre-sql-file=file- The file whose SQL is written after the pre-SQL when the plan contains a
CONCURRENTLYindex statement. The environment variable isPISTA_CONCURRENTLY_PRE_SQL_FILE. --disable-index-concurrently- Ignore every
CONCURRENTLYopt-in, both the-- pista:concurrentlydirective and an inlineCREATE INDEX CONCURRENTLY. Write plainCREATE INDEXandDROP INDEXinstead. This option cannot be used with--force-index-concurrently. The environment variable isPISTA_DISABLE_INDEX_CONCURRENTLY. --force-index-concurrently- Write
CONCURRENTLYon everyCREATE INDEXandDROP INDEX. This includes the drop of an index that the desired schema no longer contains, which no directive can reach. The environment variable isPISTA_FORCE_INDEX_CONCURRENTLY. --bulk-alter- Merge consecutive
ALTER TABLEactions on one table into one statement. Only column and constraint actions are merged. Foreign keys,RENAME,VALIDATE CONSTRAINT, row-level security toggles, storage parameters and skipped drops remain separate. The-- pista:bulk-alterdirective does the same for one table. The environment variable isPISTA_BULK_ALTER. --assume-validated- Treat every table constraint, domain constraint and foreign key as validated.
NOT VALIDin the desired schema is ignored. NeitherNOT VALIDnorVALIDATE CONSTRAINTis written. This option is for a schema in whichNOT VALIDwas a migration step, not a desired state. The environment variable isPISTA_ASSUME_VALIDATED.
Output¶
--explain- Add a comment to each statement that scans or rewrites a table. The comment says what the statement does, what its lock blocks, and the table's row and byte estimate from
pg_class. The environment variable isPISTA_EXPLAIN. See Explaining a plan. --out=file- Also write the plan to file, for
pista apply-from. The plan is fixed when it is written.apply-fromruns these statements. It checks only that the schema has not changed since and that the server's major version is the same. A-- pista:executecheck is evaluated now. A check that cannot be evaluated is an error. The environment variable isPISTA_OUT. See Plan files. --check- Exit with 2 when the plan contains executable DDL. The output does not change. The environment variable is
PISTA_CHECK.
Exit status¶
The exit status is 0 when the plan was printed, 1 on error, and 80 on a usage error. With --check, it is 2 when the plan contains executable DDL. A skipped drop alone is not executable DDL, so the exit status is 0.
Environment¶
Every option names its variable above. PISTA_CONFIG and PISTA_PAGER are described under Commands.
Notes¶
Every connection sets search_path to public. A server-side ALTER ROLE ... SET search_path therefore has no effect on it. --search-path sets another value. PostgreSQL's own default, "$user", public, is not used. With that default, the objects of a schema named after the connecting role would be read without their schema. The role that runs migrations is often not the role that the application connects as.
The catalog reports an object that is reachable through search_path without its schema. dump writes the object as the catalog reports it. plan compares that form against the desired schema. So if the desired schema qualifies an object that the catalog reports without a schema, plan finds a difference on every run. Under --search-path= every object keeps its schema. Under --search-path=myschema the objects in myschema lose their schema. Under the default, the objects in public lose their schema.
apply sets search_path to the target schemas plus public, so that an unqualified reference resolves. plan does the same before it evaluates a -- pista:execute check. The plan output contains no such SET. So piping pista plan -n myschema into psql can fail on an unqualified reference. Qualify the reference, or run pista apply.
Examples¶
Plan against the default connection, then with drops allowed:
pista plan schema.sql
pista plan --allow-drop all schema.sql
Plan a schema that is split across files:
pista plan schema/*.sql
Detect drift in CI from the exit code:
pista plan --check schema.sql
echo $? # 0: no changes, 2: changes, 1: error
Write a plan file for a later apply:
pista plan --out plan.json schema.sql
pista apply-from plan.json
Prepend a statement timeout:
pista plan --pre-sql "SET statement_timeout = '5s';" schema.sql
See also¶
pista apply, pista diff, pista dump, Directives, Controlling drops, Filtering what is managed