Skip to content

fix(migration): quote table names in create_hypertable calls#179

Merged
TerrifiedBug merged 1 commit intomainfrom
fix/timescaledb-hypertable-case-sensitivity
Apr 26, 2026
Merged

fix(migration): quote table names in create_hypertable calls#179
TerrifiedBug merged 1 commit intomainfrom
fix/timescaledb-hypertable-case-sensitivity

Conversation

@TerrifiedBug
Copy link
Copy Markdown
Owner

Summary

Migration `20260329000000_timescaledb_hypertables` calls `create_hypertable('PipelineMetric', ...)` (and the same pattern for `NodeMetric`, `PipelineLog`, `NodeStatusEvent`). PostgreSQL parses the first argument as a `regclass`, and `regclass` input folds unquoted identifiers to lowercase. So the lookup becomes `pipelinemetric`, which doesn't exist — Prisma created the table as case-preserved `"PipelineMetric"`.

Symptom on a TimescaleDB-enabled database (e.g. the new hosted demo on `timescale/timescaledb:2.16.0-pg16`):

```
ERROR: relation "pipelinemetric" does not exist
PL/pgSQL function inline_code_block line 17 at PERFORM
```

Fix: embed the case-preserved identifier inside the regclass string literal — `'PipelineMetric'` → `'"PipelineMetric"'` — for all four tables.

Why this didn't surface earlier

The whole block sits under `IF EXISTS (SELECT 1 FROM pg_extension WHERE extname = 'timescaledb')`, so plain-Postgres deployments silently no-op'd this migration. The demo environment is the first one in the wild to actually have the `timescaledb` extension, which is why we're only seeing it now.

Recovery instructions

For anyone whose DB is currently in the failed state (only TimescaleDB users; plain-Postgres users are unaffected):

Option A — wipe and reapply (cleanest if no real data):
```sh
docker compose down -v
docker compose up
```

Option B — preserve data:
```sh

Mark the failed migration as rolled back

npx prisma migrate resolve --rolled-back 20260329000000_timescaledb_hypertables

Apply the corrected migration

npx prisma migrate deploy
```

Drift warning for plain-Postgres users

The migration's checksum changes. On next `prisma migrate deploy` you may see a "migration was modified after applied" warning. Resolve with:

```sh
npx prisma migrate resolve --applied 20260329000000_timescaledb_hypertables
```

This is a one-time fix; the no-op effect on plain Postgres is unchanged.

Test plan

  • Visual inspection of the four `PERFORM create_hypertable` calls — every table-name argument is now wrapped in escaped quotes
  • Pull this branch into the demo deployment, wipe the postgres volume, restart — migrations apply cleanly through to the end
  • Verify hypertables exist: `SELECT hypertable_name FROM timescaledb_information.hypertables;` — should show all four

References

PostgreSQL's regclass input function folds unquoted identifiers to
lowercase. The previous form 'PipelineMetric' was looked up as
pipelinemetric and failed with 'relation does not exist' on every
TimescaleDB-enabled deployment (the demo environment surfaced this).

Plain-PostgreSQL deployments were unaffected because the surrounding
IF EXISTS check made the entire block a no-op there.

Fix: embed the case-preserved identifier inside the regclass string
literal so it survives the regclass cast.
@github-actions github-actions Bot added the fix label Apr 26, 2026
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 26, 2026

Greptile Summary

This PR fixes a PostgreSQL regclass case-folding bug in the TimescaleDB migration: passing 'PipelineMetric' (unquoted inside the string) caused the identifier to be folded to lowercase and fail with "relation does not exist". The fix — wrapping each table name in embedded double-quotes ('"PipelineMetric"') — is applied correctly and consistently to all four hypertable calls, the explanatory comment is accurate, and the IF EXISTS (timescaledb) guard continues to make the migration a no-op on plain-Postgres deployments.

Confidence Score: 5/5

Safe to merge — targeted one-line fix per table with no side effects on plain-Postgres deployments.

The change is minimal and correct: all four create_hypertable calls receive the properly quoted regclass string, the if_not_exists => true flag keeps the migration idempotent, and the TimescaleDB guard ensures plain-Postgres environments are unaffected. No logic, security, or data-integrity concerns were found.

No files require special attention.

Important Files Changed

Filename Overview
prisma/migrations/20260329000000_timescaledb_hypertables/migration.sql Adds embedded double-quotes to all four create_hypertable() regclass arguments to preserve case; fix is applied consistently and a clear explanatory comment is added.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[prisma migrate deploy] --> B{TimescaleDB\nextension present?}
    B -- No --> C[RAISE NOTICE: skipping\n plain-Postgres no-op]
    B -- Yes --> D[DROP + recreate composite PKs\nid + timestamp]
    D --> E["create_hypertable('PipelineMetric', ...)"]
    E --> F["create_hypertable('NodeMetric', ...)"]
    F --> G["create_hypertable('PipelineLog', ...)"]
    G --> H["create_hypertable('NodeStatusEvent', ...)"]
    H --> I[RAISE NOTICE: hypertables created]

    style E fill:#d4edda,stroke:#28a745
    style F fill:#d4edda,stroke:#28a745
    style G fill:#d4edda,stroke:#28a745
    style H fill:#d4edda,stroke:#28a745
Loading

Reviews (1): Last reviewed commit: "fix(migration): quote table names passed..." | Re-trigger Greptile

@TerrifiedBug TerrifiedBug merged commit 238dc42 into main Apr 26, 2026
8 checks passed
@TerrifiedBug TerrifiedBug deleted the fix/timescaledb-hypertable-case-sensitivity branch April 26, 2026 16:39
TerrifiedBug added a commit that referenced this pull request Apr 26, 2026
…ings (#181)

TimescaleDB's parser for compress_segmentby and compress_orderby folds
unquoted identifiers to lowercase (same behaviour as PostgreSQL's
regclass parser, which bit us in #179). Prisma's columns are camelCase
('pipelineId', 'nodeId'), so 'pipelineId' was being looked up as
'pipelineid' and the migration failed with:

  ERROR: column "pipelineid" does not exist
  HINT: The timescaledb.compress_segmentby option must reference a valid column.

Wrap every column name in double quotes inside the option strings —
the same pattern used for the table-name argument in #179.
TerrifiedBug added a commit that referenced this pull request Apr 26, 2026
#182)

Bare SELECT inside a PL/pgSQL DO block is invalid when the result is
discarded — Postgres raises 42601 "query has no destination for result
data". Switch the four add_compression_policy calls to PERFORM so the
migration applies cleanly on TimescaleDB.

Follows #179, #180, #181 — same file, same DO block.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant