Query icon
OutputValues icon
Log icon
If icon
SlackIncomingWebhook icon
Loop icon
Fail icon
Schedule icon

DB2 Reorg-Pending Maintenance Guard

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.

Categories
DataInfrastructure

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.

Findings

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.

How it works

  1. 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.
  2. plan (io.kestra.plugin.core.output.OutputValues) collects the quoted names into a list. summary logs the count and the names.
  3. route (io.kestra.plugin.core.flow.If) branches on whether any table is pending:
    • clean: logs that nothing is pending in the schema.
    • 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.
  4. errors posts a Slack alert when the flow fails, for example when the database is unreachable.

What you get

  • The exact tables locked out by reorg-pending state, from the catalog rather than from guesswork.
  • A safe default: the flow reports and never changes anything unless you ask it to.
  • A classic REORG and RUNSTATS per table, serialized, with a second read of the flag as proof the state actually cleared.

Who it's for

  • DBAs who have hit a table that stopped answering queries after a migration.
  • Platform teams running DB2 who want reorg-pending caught on a schedule instead of by a page.
  • Teams evaluating the DB2 plugin who want an example that drives ADMIN_CMD utilities.

Why orchestrate this with Kestra

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.

Tested end to end

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

Prerequisites

  • A DB2 user that can run SYSPROC.ADMIN_GET_TAB_INFO and, for remediation, call SYSPROC.ADMIN_CMD to REORG and RUNSTATS the tables. The instance owner has both.
  • Local testing:
    • docker run -d --name db2 --privileged -p 50000:50000 -e LICENSE=accept -e DB2INST1_PASSWORD=... -e DBNAME=testdb icr.io/db2_community/db2:latest;
    • create a table, insert rows, then run three ALTER TABLE ... DROP COLUMN statements to push it into reorg-pending.

Secrets

  • DB2_PASSWORD: the database password, used as the default for the jdbc_password input.
  • SLACK_WEBHOOK_URL: used by alert and the errors block.
  • In Kestra OSS, provide each one as a base64-encoded environment variable prefixed SECRET_.

Inputs

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

Quick start

  1. Add the DB2_PASSWORD and SLACK_WEBHOOK_URL secrets.
  2. Import the flow, set jdbc_url and jdbc_username, then set table_schema to the schema you want to scan.
  3. Run it once and read the tables reported as pending.
  4. When you are ready to act, run with auto_remediate: true and dry_run: false.
  5. Enable the daily trigger, which always runs in safe mode.

How to extend

  • Add a Pause before remediate so a human approves the reorg window, since a classic reorg locks the table.
  • Read NUM_REORG_REC_ALTERS from ADMIN_GET_TAB_INFO to warn on tables close to the limit before they reach reorg-pending.
  • Also act on reorg-recommended (soft) state to reclaim space on bloated tables.
  • Loop over several schemas or databases to cover a whole instance.

Links

See How

New to Kestra?

Use blueprints to kickstart your first workflows.