New to Kestra?
Use blueprints to kickstart your first workflows.
Find DB2 tables in reorg-pending state with ADMIN_GET_TAB_INFO, alert Slack, then clear them with a classic REORG and RUNSTATS through ADMIN_CMD and verify.
A DB2 table enters reorg-pending state after a run of schema changes. DB2 allows three
reorg-recommended ALTER TABLE operations (dropping a column, changing a column type and the
like) on a table. The third one leaves the table in reorg-pending state. From that point
the table is effectively locked: queries and further alters against it fail until someone
reorganizes it. The flag is easy to miss because the ALTER statements all succeed. The
outage only shows up when an application reads the table.
This blueprint reads reorg-pending state from SYSPROC.ADMIN_GET_TAB_INFO for the schema you
point it at and alerts Slack. When it is allowed to act it runs a classic REORG followed by
RUNSTATS through SYSPROC.ADMIN_CMD, one table at a time, then reads the state again and
fails the run if any table is still pending.
This blueprint was created by zkasuran.
| Finding | Why it matters |
|---|---|
REORG_PENDING = 'Y' |
The table is locked out until it is reorganized. Reads and alters against it fail |
Reorg-pending (the hard state) is not the same as reorg-recommended (the soft state that only
suggests a reorg would help). The hard state is cleared by a classic REORG TABLE, which
rebuilds the table offline. An INPLACE (online) reorg is rejected on a table in reorg-pending
state, so this blueprint runs a classic reorg. RUNSTATS then refreshes the optimizer
statistics the rebuild invalidates.
Both commands go through SYSPROC.ADMIN_CMD, because REORG and RUNSTATS are DB2 utility
commands, not plain SQL statements that a driver can prepare and run on their own.
The scan calls ADMIN_GET_TAB_INFO with an explicit schema argument. A scan of the
SYSIBMADM.ADMINTABINFO view with a LIKE filter on TABSCHEMA does not reliably surface a
freshly pending table, so the guard takes one schema per run.
detect (io.kestra.plugin.jdbc.db2.Query, read-only) calls
TABLE(SYSPROC.ADMIN_GET_TAB_INFO(:table_schema, NULL)) and returns one row per table with
REORG_PENDING = 'Y'. Each row carries the display name and the quoted "SCHEMA"."TABLE"
identifier used to build the commands.plan (io.kestra.plugin.core.output.OutputValues) collects the quoted names into a list.
summary logs the count and the names.route (io.kestra.plugin.core.flow.If) branches on whether any table is pending:alert posts the tables to Slack.remediate_gate runs only when auto_remediate is true and dry_run is false.remediate (io.kestra.plugin.core.flow.Loop, concurrencyLimit: 1) reorganizes one
table at a time: reorg calls ADMIN_CMD('REORG TABLE ...'), then runstats calls
ADMIN_CMD('RUNSTATS ON TABLE ...'). The command text is bound as a parameter.reverify reads ADMIN_GET_TAB_INFO again and verify_result fails the run if any
table is still pending.errors posts a Slack alert when the flow fails, for example when the database is
unreachable.ADMIN_CMD utilities.Reorg-pending is set quietly by routine schema changes and only bites later, so it needs a
regular check rather than a human remembering to look. Kestra runs the scan on a schedule,
sends the locked tables to Slack, applies the reorg only behind auto_remediate and dry_run,
one table at a time so a batch of reorgs does not all contend at once, verifies the result and
keeps a history of every run.
On Kestra 2.0.5 OSS against DB2 Community Edition (icr.io/db2_community/db2), database
testdb, with a local HTTP sink standing in for Slack. A table was pushed into reorg-pending
by three ALTER TABLE ... DROP COLUMN statements, confirmed with
SELECT REORG_PENDING FROM TABLE(SYSPROC.ADMIN_GET_TAB_INFO('EXP3', NULL)) reading Y.
| Run | Inputs | Result |
|---|---|---|
| 1 | table_schema: CLEANSCHEMA |
0 tables pending, clean branch, no change |
| 2 | table_schema: EXP3 |
1 table pending (EXP3.R), alert sent, CLI still Y, no change |
| 3 | table_schema: EXP3, auto_remediate: true, dry_run: true |
Same report, CLI still Y, safe mode made no change |
| 4 | table_schema: EXP3, auto_remediate: true, dry_run: false |
REORG and RUNSTATS ran, reverify found 0 pending, CLI read N |
| 5 | unreachable port | Flow failed, errors posted the Slack alert |
SYSPROC.ADMIN_GET_TAB_INFO and, for remediation, call
SYSPROC.ADMIN_CMD to REORG and RUNSTATS the tables. The instance owner has both.docker run -d --name db2 --privileged -p 50000:50000 -e LICENSE=accept -e DB2INST1_PASSWORD=... -e DBNAME=testdb icr.io/db2_community/db2:latest;ALTER TABLE ... DROP COLUMN statements to push it into reorg-pending.DB2_PASSWORD: the database password, used as the default for the jdbc_password input.SLACK_WEBHOOK_URL: used by alert and the errors block.SECRET_.| Input | Default | Purpose |
|---|---|---|
jdbc_url |
jdbc:db2://localhost:50000/testdb |
Database to scan |
jdbc_username |
db2inst1 |
Database user |
jdbc_password |
{{ secret('DB2_PASSWORD') }} |
Database password |
table_schema |
DB2INST1 |
Schema scanned, passed to ADMIN_GET_TAB_INFO (case sensitive) |
runstats_options |
WITH DISTRIBUTION AND DETAILED INDEXES ALL |
RUNSTATS clause |
auto_remediate |
false |
Allow REORG and RUNSTATS |
dry_run |
true |
Must be false for a reorg to run |
DB2_PASSWORD and SLACK_WEBHOOK_URL secrets.jdbc_url and jdbc_username, then set table_schema to the schema you
want to scan.auto_remediate: true and dry_run: false.daily trigger, which always runs in safe mode.Pause before remediate so a human approves the reorg window, since a classic reorg
locks the table.NUM_REORG_REC_ALTERS from ADMIN_GET_TAB_INFO to warn on tables close to the limit
before they reach reorg-pending.