questdb / questdb/questdb

SQL view updates lose SELECT * coverage for later-added columns

Open
#7,621 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Bug Security SQL
Dominant language
Java
Stars
17.3k
Forks
1.6k
Avg merge
5d 10h
Merged PRs (30d)
28

Description

Problem

A view created with SELECT * should include columns added to its source table later. But running ALTER VIEW ... AS (SELECT * ...) makes the view remember only the columns that exist today.

After someone adds a column, users who can read the view but not the source table may get permission errors when reading the new column through the view. SELECT * FROM v can fail too.

This problem exists before PR #7263. It does not require a retention policy or two operations running at the same time.

PR #7263 adds another way to trigger it: if a retention policy changes while CREATE VIEW is finishing, CREATE takes a recovery path with the same mistake. The policy change can even concern an unrelated materialized view. Normal CREATE remembers * correctly.

How to reproduce the existing ALTER problem

  1. Create a table t and a view v using SELECT * FROM t.
  2. Give a user SELECT permission on v, but no direct SELECT permission on t.
  3. As an administrator, run ALTER VIEW v AS (SELECT * FROM t).
  4. Add a column w to t and wait for the database to apply the change.
  5. As the user from step 2, run SELECT w FROM v or SELECT * FROM v.

Expected: the user can read the new column through the view.

Reported result: the query requires direct SELECT permission on t.w and fails. Skipping step 3 lets the user read the new column normally.

Why it happens

The database stores which tables and columns a view uses. That list also controls which columns users may read through the view without direct permission on the source table.

Normal CREATE remembers both the original * and the columns the query needs after optimization. ALTER and the new CREATE recovery path look only at the optimized query, where * has already become a list of today's columns. They save that list and lose the promise to include future columns.

The timing overlap in CREATE only selects the broken path. The underlying mistake is that these paths build the list differently.

Evidence

The review of PR #7263, item 1 and its separate pre-existing finding, reports:

  • Before the PR (ae326748) and at the reviewed PR version (cca0dee6), CREATE keeps * but ALTER loses it: createdStar=true alteredStar=false.
  • When a test forces a policy change during CREATE, normal CREATE keeps * but the recovery path loses it: controlStar=true racedStar=false.
  • In both broken cases, the user cannot read a later-added column with permission on the view alone.

These test results come from the linked review. We inspected the code for this follow-up but did not rerun those tests. The review lists its local logs under /tmp/pr7263-review-EDgeSF/; those logs are not attached to this issue.

Relevant code:

Impact

Moderate. Enterprise users who can read a view but not its source table may get lasting permission errors after someone adds a column. Retrying the query or restarting the server does not repair the saved column list.

The CREATE case requires two operations to overlap. The ALTER case does not. This issue does not show lost data, incorrect retention cleanup, or access to data the user should not see.

What to fix and test

  • Have CREATE, ALTER and CREATE recovery use the same code to build the view's table and column list. Keep * as well as columns needed by retention filters.
  • Add a test for ordinary ALTER and another that forces a policy change during CREATE recovery, rather than relying on chance timing.
  • Check that the saved definition keeps * and that a user with permission only on the view can read a later-added column, including after a restart.
  • Keep tests for views that name specific columns and for columns used by retention filters, so the fix does not grant more access than intended.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in core/src/main/java/io/questdb/griffin/SqlCompilerImpl.java, comparing the ALTER, normal CREATE, and CREATE recovery paths linked in the issue; also read the permission check in core/src/main/java/io/questdb/cairo/AbstractPartitionFrameCursorFactory.java. Add tests for ordinary ALTER and forced CREATE recovery, including restart behavior, later-added columns, specific-column views, and retention filters. Done means view-only users can read later-added columns without granting unintended access.

Written by the indexing model from the issue text.

Assessment

Tech stack
java, sql
Domain
authorization, databases
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
68/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.