Skip to content

fix: selecting empty columns returns primary keys - #85

Merged
edgurgel merged 1 commit into
masterfrom
fix/select-empty-returns-primary-keys
Aug 28, 2026
Merged

edgurgel merged 1 commit into
masterfrom
fix/select-empty-returns-primary-keys

Conversation

@edgurgel

Copy link
Copy Markdown
Member

What kind of change does this PR introduce?

We always include primary keys so it makes sense to return them when select is empty instead of erroring out

What is the current behavior?

empty select errors out

What is the new behavior?

empty select returns primary keys

Nicer diff:

--- a/subscription_check_filters (prev, migration 0015)
+++ b/subscription_check_filters (new, migration 0017)
@@ -122,22 +122,16 @@
                 raise exception 'invalid regular expression for % filter: %', filter_v2.op::text, sqlerrm;
             end;
         else
             -- eq/neq/lt/lte/gt/gte/isdistinct: value must be coercable to the type
             perform realtime.cast(filter_v2.value, col_type);
         end if;
     end loop;

-    -- Reject empty selected_columns: array_agg would silently convert '{}' to NULL
-    -- during normalization, making it indistinguishable from "all columns"
-    if new.selected_columns = '{}' then
-        raise exception 'selected_columns cannot be empty. Remove the select parameter to capture all columns.';
-    end if;
-
     -- Reject arrays with NULL elements which bypass column validation
     if new.selected_columns is not null and array_position(new.selected_columns, null::text) is not null then
         raise exception 'selected_columns cannot contain null values.';
     end if;

     -- Validate that selected_columns reference columns the role can SELECT
     if new.selected_columns is not null then
         for selected_col in select * from unnest(new.selected_columns) loop
@@ -155,17 +149,24 @@
     ) from unnest(new.filters) f;

     new.filters_v2 = coalesce(
         array_agg(f order by f.column_name, f.op, f.value, f.negate),
         '{}'
     ) from unnest(new.filters_v2) f;

     -- Normalize selected_columns order so ARRAY['a','b'] and ARRAY['b','a'] are
-    -- treated as the same subscription group in apply_rls
-    new.selected_columns = (
-        select array_agg(c order by c)
-        from unnest(new.selected_columns) c
-    );
+    -- treated as the same subscription group in apply_rls. Preserve an empty
+    -- array as '{}' ("primary keys only") so it stays distinct from NULL ("all
+    -- columns"); array_agg over an empty set would otherwise collapse it to NULL.
+    if new.selected_columns is not null then
+        new.selected_columns = coalesce(
+            (
+                select array_agg(c order by c)
+                from unnest(new.selected_columns) c
+            ),
+            '{}'::text[]
+        );
+    end if;

     return new;
 end;
 $$;

We always include primary keys so it makes sense to return them
when select is empty instead of erroring out
@edgurgel
edgurgel merged commit 493794f into master Aug 28, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants