Closes#47012
## What kind of change does this PR introduce?
Bug fix.
## What is the current behavior?
Unencrypted FDW server option values are pre-escaped with
`literal(value).replace(/'/g, "''")` and embedded inside the outer
`create server` `E'...'` string built by `format()`. That nests the
value inside two `E'...'` literals, so backslashes are decoded twice. A
value like `domain\user` aborts wrapper creation with `invalid Unicode
escape`, and `p@ss\w0rd` is silently stored as `p@ssw0rd`.
## What is the new behavior?
Unencrypted option values are passed as `format()` `%L` arguments, the
same way the encrypted options already supply their secret id, so
Postgres escapes each value exactly once.
Before and after, on postgres:16:
| Value | Before | After |
| --- | --- | --- |
| `domain\user` | aborts (invalid Unicode escape) | stored `domain\user`
|
| `p@ss\w0rd` | stored `p@ssw0rd` | stored `p@ss\w0rd` |
| `a\b` | stored `a`+backspace | stored `a\b` |
## Additional context
Added a unit test in `packages/pg-meta/test/sql/studio/fdw.test.ts`
asserting unencrypted options use a `%L` placeholder with the value as a
`format()` argument, and that the old double-escaped form is gone. The
encrypted-option path is unchanged.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Improved handling of special characters in foreign data wrapper server
option values.
* **Tests**
* Added test coverage for foreign data wrapper configuration, including
edge cases with special characters.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
- closes https://github.com/supabase/supabase/issues/47033
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Table search now matches fully-qualified table names (e.g.,
`schema.table`) when no specific schema is selected, enabling searches
to work seamlessly across all schemas.
* **Tests**
* Added comprehensive test coverage validating schema-qualified table
name matching in search filters.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## I have read the
[CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md)
file.
YES
## What kind of change does this PR introduce?
Performance improvement / feature
## What is the current behavior?
The Schema Designer fetches all tables in a single request via
`useTablesQuery`. For schemas with 400+ tables this blocks first paint
on a large payload.
## What is the new behavior?
`SchemaGraph` uses `useInfiniteTablesQuery` (pageSize: 100) so the first
100 tables paint immediately. A "Load more tables" button appears above
the legend whenever more pages remain, letting users load the rest on
demand.
## Additional context
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Added a "Find table…" selector and keyboard shortcut to quickly locate
and focus tables; supports incremental loading and debounced name search
(with literal wildcard handling).
* Schema Graph shows a bottom "Load more tables" control with loading
state and preserves view after loading more.
* **Refactor**
* Table listing switched to infinite/paginated retrieval and improved
"no tables" logic; server-side name filtering supported.
* **Tests**
* E2E tests add a schema-visualizer wait helper and update flows to
support the paginated visualizer.
<!-- review_stack_entry_start -->
[](https://app.coderabbit.ai/change-stack/supabase/supabase/pull/46402?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)
<!-- review_stack_entry_end -->
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## I have read the
[CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md)
file.
YES
## What kind of change does this PR introduce?
Feature — adds a new data-layer hook. No callers are switched over in
this PR.
## What is the current behavior?
The Schema Designer and Database > Tables list both call
`useTablesQuery({ includeColumns: true })`, which fetches the full
schema (every table, with every column, every relationship) in one
round-trip. For customers with many tables this never loads. Towards
FE-3428.
## What is the new behavior?
Introduces `useInfiniteTablesQuery` — a cursor-paginated tables hook
ready to be consumed by the two pages above in follow-up PRs.
- `pg-meta`: new `getTablesPaginatedSql` SQL builder that picks a page
of table OIDs first (cheap `pg_class` index scan) and constrains every
enrichment CTE (primary keys, relationships, columns) to that set.
Pagination is by `c.oid > $afterOid` rather than `OFFSET`, so deep pages
stay O(limit). Relationships use a `UNION ALL` keyed by `table_id` so
the downstream join is a plain equi-join.
- `pg-meta`: `COLUMNS_SQL` is now produced by `getColumnsSql({ filter
})`, letting a paginating caller push a table-OID predicate into the
WHERE clause directly. The bare `COLUMNS_SQL` export is preserved for
the 5 existing callers (`pg-meta-columns`, `pg-meta-tables`,
`pg-meta-views`, `pg-meta-materialized-views`,
`pg-meta-foreign-tables`).
- `studio`: `useInfiniteTablesQuery` wires the new SQL into
`useInfiniteQuery` via `executeSql`. `initialPageParam: 0`,
`getNextPageParam` returns the last row's `id` or `undefined` on a short
last page.
- Tests: 12 new tests in `pg-meta` covering cursor invariants (no
overlap / no gap), schema filtering, primary-key / relationship / column
shape, and output parity against the existing `pgTableZod` schema.
## Additional context
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Enabled infinite scrolling for table listings with cursor-based
pagination and optional page sizing.
* Added an option to include per-table column data in paginated results.
* Made column queries filterable for more targeted metadata retrieval.
* **Tests**
* Added comprehensive tests validating pagination, schema scoping,
column inclusion, and relationship/PK shaping.
<!-- review_stack_entry_start -->
[](https://app.coderabbit.ai/change-stack/supabase/supabase/pull/46285?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)
<!-- review_stack_entry_end -->
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Refactor**
* Improved SQL construction across the studio to make queries safer and
more consistent.
* Safer parameter handling for optional schema and remediation links to
prevent injection risks.
* Deterministic query header formatting and stable date/comments in
generated SQL.
* More robust user-count and paginated-user queries for accurate counts,
sorting and pagination.
* Updated tests to align with the new safe query handling.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## Context
Shifts all remaining dashboard queries into pg-meta so that we
centralize all manually written queries in one place
Having them in packages/pg-meta also allows us to write tests for them
## To test
Just needs a smoke test on
- Role Impersonation
- Lints
- Data API
- Database
- Enumerated Types
- Integrations
- Foreign Data Wrappers
- Vault
## Context
We reached to a consensus that we'll keep manually written queries
within the `pg-meta` package
I'll shift queries over in several PRs but wanted to double check if the
changes here is a good folder structure
## Changes involved
- Am organizing dashboard queries in `pg-meta` based on product
- So folder structure will be `/sql/studio/[product]/*.ts`
- Every constant will be exported directly from `pg-meta`'s index
- So consumption in dashboard will just be `import { xxx } from
'@supabase/pg-meta`
cc @avallete and @soedirgo on this one - lemme know if this is alright,
or if there's a preferred way to do this
Sorted all imports in all packages, `cms`, `design-system` and
`ui-library` apps by running `pnpm format` on them.
All changes in this PR are done by the script.
* Updated to use optimized search columns when getting user counts
* added unit tests for query builders
* minor
* Nit fix keywords URL param not getting loaded into search input field
* removed user footer
* updated tests for upstream
* updated integration tests
* updated tests to be int for paginated
* updated schema
* updated types
* updated type imports
* updated type imports
* Apply suggestion from @avallete
Co-authored-by: Andrew Valleteau <avallete@users.noreply.github.com>
* updated literal import
* refactor: use common escaping (#40186)
refactor: use utils for sql escaping
---------
Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
Co-authored-by: Andrew Valleteau <avallete@users.noreply.github.com>