docs: flip ownership of View/SQL-client/FTS-SQL/AuthZ/AuthN to OSS, restructure SQL Reference

OSS docs now own the full usage content for features that only run against
an Enterprise deployment, since the client interface itself lives here;
Enterprise docs keep only the parts specific to its own behavior. Sophon's
overlay for these five pages is dropped since the OSS versions are now the
complete reference.

SQL Reference is restructured to match an object-type SQL manual (DDL by
object, then DML, then DQL, then Expressions) instead of the old flat,
loosely-ordered page list, absorbing the SQL client-connection guide and
FTS-via-SQL examples into it.
This commit is contained in:
Jack Ye
2026-09-28 17:17:09 -05:00
parent cb45b67c4c
commit 52684d50b9
57 changed files with 1412 additions and 590 deletions
+86
View File
@@ -0,0 +1,86 @@
---
title: "Function"
sidebarTitle: "Function"
description: "CREATE FUNCTION, SHOW FUNCTIONS, and DROP FUNCTION."
icon: function
keywords: ["create function", "drop function", "show functions", "sql", "udf"]
---
<Badge color="red">Enterprise</Badge> [SQL runs on a deployment.](/sql)
## CREATE FUNCTION {#create}
```sql
CREATE FUNCTION f(x BIGINT) RETURNS BIGINT
LANGUAGE python
AS 'def f(x): return x * 2'
WITH (pip = 'numpy==1.26.4', python_version = '3.11')
```
The body is Python source. Its dependencies are declared with it and are part
of the **immutable function version** -- changing one produces a new version
rather than altering the registered one, so a column filled by an earlier
version is unaffected.
| Option | |
| --- | --- |
| `pip` | pip requirements for the worker environment |
| `conda` | conda packages instead of pip |
| `conda_channels` | channels in priority order; requires `conda` |
| `python_version` | worker Python version, defaulting to yours |
| `gpu` | `'true'` when every execution needs a GPU |
**Errors and limits**
| | |
| --- | --- |
| `LANGUAGE` other than `python` | refused |
| `pip` and `conda` together | refused -- pick one |
| `conda_channels` without `conda` | refused |
| `gpu` set to anything but `'true'` | refused |
| An empty body | refused |
| Any other option | refused, and the message lists what is supported |
<Note>
**Enterprise job type:** `create_function`. Registration returns a job because
the function is baked into an image before the version becomes usable.
</Note>
## SHOW FUNCTIONS {#show}
```sql
SHOW FUNCTIONS
```
Lists registered functions and their versions. Since a version is immutable
and a column pins the version that fills it, this is how you find which
versions are still in use before dropping one.
## DROP FUNCTION {#drop}
```sql
DROP FUNCTION embed WITH (version = '1')
DROP FUNCTION IF EXISTS embed WITH (version = '1')
DROP FUNCTION embed WITH (version = '1', cascade = 'true')
```
`version` is required -- a function is a set of immutable versions, and
dropping is always of one specific version, never "the function" as a whole.
<Warning>
Without `cascade = 'true'`, dropping a version that a column still pins fails
rather than breaking that column silently. Passing it drops the version and
lets columns pinned to it stop refreshing -- they keep their last-filled
values, per [Guarantees](/basics/guarantees#jobs).
</Warning>
## What to read next {#next}
<CardGroup cols={2}>
<Card title="Function" icon="function" href="/management/function">
Registering one from the SDK, and diagnosing environment mismatches.
</Card>
<Card title="Computed columns" icon="table-columns" href="/feature-engineering/add-computed-column">
Filling a column with a function instead of an expression.
</Card>
</CardGroup>
+49
View File
@@ -0,0 +1,49 @@
---
title: "Index"
sidebarTitle: "Index"
description: "CREATE INDEX and DROP INDEX — one column, server-chosen name."
icon: bolt
keywords: ["create index", "drop index", "sql"]
---
<Badge color="red">Enterprise</Badge> [SQL runs on a deployment.](/sql)
## CREATE INDEX {#create}
```sql
CREATE INDEX ON documents (title)
```
<Note>
SQL `CREATE INDEX` covers **one column** and takes **no user-chosen name** --
the server names it. For a multi-column or explicitly-named index, or to
choose the algorithm, use the SDK's
[`create_index`](/indexing#choosing-an-index).
</Note>
<Note>
**Enterprise job type:** `create_ivf_pq`, `create_btree`, `create_fts`, and one
more per algorithm -- the type names which algorithm is building, not a
different feature. See [Build & Repair](/indexing/reindexing).
</Note>
## DROP INDEX {#drop}
```sql
DROP INDEX documents.title_idx
```
Takes the qualified `table.index` name. Find it with the SDK's
[`list_indices`](/indexing#choosing-an-index) if you created the index without
naming it yourself.
## What to read next {#next}
<CardGroup cols={2}>
<Card title="Indexing" icon="bolt" href="/indexing">
Choosing an index type from the SDK.
</Card>
<Card title="Build & Repair" icon="refresh" href="/indexing/reindexing">
Keeping an index current as data arrives.
</Card>
</CardGroup>
+90
View File
@@ -0,0 +1,90 @@
---
title: "Job"
sidebarTitle: "Job"
description: "SHOW JOBS, SHOW ERRORS, and controlling a running job with PAUSE, RESUME and CANCEL."
icon: hourglass-half
keywords: ["show jobs", "show errors", "pause job", "resume job", "cancel job", "sql"]
---
<Badge color="red">Enterprise</Badge> [SQL runs on a deployment.](/sql)
A [job](/basics/jobs) is not a catalog object -- it has no schema and is not
namespaced -- but it has its own SQL statements, grouped here the same way the
catalog objects are.
## SHOW JOBS {#show}
```sql
SHOW JOBS
```
Every job the server knows about -- id, type, state, creation time. The SQL
counterpart of `list_jobs`.
## SHOW ERRORS {#errors}
```sql
SHOW ERRORS ON <table> [FOR JOB '<job-id>'] [LIMIT <n>]
```
```sql
SHOW ERRORS ON documents
SHOW ERRORS ON documents FOR JOB 'job-abc' LIMIT 100
```
Why rows failed. Reach for this when a [refresh](/sql/dml/refresh) reports
fewer filled rows than you expected.
**Errors and limits**
| | |
| --- | --- |
| `LIMIT` | must be between 1 and 100,000 |
| Failed jobs scanned without `FOR JOB` | 32 most recent |
| Tables the server does not open directly | not supported |
Without `FOR JOB` this surveys recent failures and stops at 32 jobs. When the
listing stops at your `LIMIT`, the message says so -- narrow with `FOR JOB`
rather than raising the limit blindly.
## PAUSE JOB {#pause}
```sql
PAUSE JOB 'j-ci-abc-def'
```
## RESUME JOB {#resume}
```sql
RESUME JOB 'j-ci-abc-def'
```
## CANCEL JOB {#cancel}
```sql
CANCEL JOB 'j-ci-abc-def'
```
The job id is always a quoted string literal. All three take exactly one and
nothing after it -- a second token on the line is a syntax error rather than
being ignored.
<Note>
Cancellation is a request, matching the SDK's
[`cancel()`](/basics/jobs#managing): it does not guarantee the job stops before
doing more work, and asking twice or cancelling a finished job does nothing.
`CANCEL JOB` itself can be unavailable on a deployment with no job registry
configured, which is a deployment condition rather than something you can work
around from SQL.
</Note>
## What to read next {#next}
<CardGroup cols={2}>
<Card title="Query and job" icon="hourglass-half" href="/basics/jobs">
The handle these statements are the SQL view of.
</Card>
<Card title="Background jobs" icon="gears" href="/maintenance/background-jobs">
Job types you did not start yourself.
</Card>
</CardGroup>
+62
View File
@@ -0,0 +1,62 @@
---
title: "Materialized View"
sidebarTitle: "Materialized View"
description: "SHOW MATERIALIZED VIEWS — creation and refresh are SDK and REFRESH statements, not CREATE."
icon: table
keywords: ["materialized view", "show materialized views", "sql"]
---
<Badge color="red">Enterprise</Badge> [SQL runs on a deployment.](/sql)
A materialized view stores a query's result as rows, kept current by a refresh
-- the counterpart to a [view](/sql/ddl/view), which stores only the query.
<Note>
There is no `CREATE MATERIALIZED VIEW` statement. Creation is
[`create_materialized_view`](/management/materialized-view#create) in the SDK,
since it needs SDK-level source-table validation (stable row ids) that a bare
SQL statement has nowhere to check. Once created, it is entirely a SQL object:
queried like a table, refreshed with SQL, listed with SQL.
</Note>
## SHOW MATERIALIZED VIEWS {#show}
```sql
SHOW MATERIALIZED VIEWS
```
<Note>
Cheaper than the SDK equivalent. `list_materialized_views` finds views by
reading every table's schema, costing one open per table; this asks the server.
</Note>
## Refreshing one {#refresh}
```sql
REFRESH MATERIALIZED VIEW chunks
```
See [REFRESH](/sql/dml/refresh#refresh-materialized-view) for the full syntax,
including `full = true` and what `CASCADE` does not yet do.
## Dropping one {#drop}
A materialized view **is** a table, so it is dropped with
[`DROP TABLE`](/sql/ddl/table#drop) -- which is also why dropping one removes
stored rows, unlike dropping a [view](/sql/ddl/view#drop).
<Note>
**Enterprise job type:** `mat_view_refresh` for the refresh; `drop_table` for
dropping it, same as any table.
</Note>
## What to read next {#next}
<CardGroup cols={2}>
<Card title="Materialized View" icon="table" href="/management/materialized-view">
Creating one from the SDK, and the stable-row-ids requirement.
</Card>
<Card title="Refresh a materialized view" icon="arrows-rotate" href="/feature-engineering/materialized-views">
Incremental refreshes, and what they cost.
</Card>
</CardGroup>
+53
View File
@@ -0,0 +1,53 @@
---
title: "Namespace"
sidebarTitle: "Namespace"
description: "CREATE SCHEMA and DROP SCHEMA — the SQL spelling of namespace DDL."
icon: folder-tree
keywords: ["namespace", "schema", "create schema", "drop schema", "sql"]
---
<Badge color="red">Enterprise</Badge> [SQL runs on a deployment.](/sql)
A [namespace](/management/namespace) is addressed in SQL as a `SCHEMA` -- the
standard's name for the same concept.
## CREATE SCHEMA {#create}
```sql
CREATE SCHEMA public
CREATE SCHEMA db1.ns1.ns2
CREATE SCHEMA IF NOT EXISTS `ns1$ns2`
```
A dotted path creates the whole chain: `db1.ns1.ns2` creates `ns2` inside
`ns1` inside `db1`, provided the parents already exist. A name containing the
namespace path delimiter itself is backtick-quoted, as in `` `ns1$ns2` `` above.
`IF NOT EXISTS` makes the statement a no-op rather than an error when the
namespace is already there.
## DROP SCHEMA {#drop}
```sql
DROP SCHEMA db1.public
DROP SCHEMA IF EXISTS `a$b`
DROP SCHEMA `a$b` RESTRICT
```
<Warning>
`CASCADE` is rejected: **"DROP SCHEMA CASCADE is not supported; drop the
objects inside first."** A namespace's tables, views and functions must be
dropped explicitly before the namespace itself can go. `RESTRICT` -- the
default -- states that requirement rather than changing it.
</Warning>
## What to read next {#next}
<CardGroup cols={2}>
<Card title="Namespace" icon="folder-tree" href="/management/namespace">
The SDK equivalent, and how a namespace fits the catalog hierarchy.
</Card>
<Card title="Table" icon="table" href="/sql/ddl/table">
Creating tables inside a namespace.
</Card>
</CardGroup>
+178
View File
@@ -0,0 +1,178 @@
---
title: "Table"
sidebarTitle: "Table"
description: "CREATE, DESCRIBE, ALTER, CLONE and DROP TABLE."
icon: table
keywords: ["create table", "alter table", "drop table", "describe", "clone", "ddl"]
---
<Badge color="red">Enterprise</Badge> [SQL runs on a deployment.](/sql)
## CREATE TABLE {#create}
```sql
CREATE TABLE documents (id BIGINT, title VARCHAR, created_at TIMESTAMP)
CREATE TABLE recent AS SELECT * FROM documents WHERE created_at > now() - INTERVAL '7 days'
```
Column types are Arrow types under SQL names -- see [Data types](/sql/data-types).
A table inside a [namespace](/sql/ddl/namespace) is written as a dotted path:
`prod.events.clicks`.
## DESCRIBE {#describe}
```sql
DESCRIBE documents
```
The table's columns and types, without a plan -- the SQL counterpart of
`table.schema`.
## ALTER TABLE {#alter}
`ALTER TABLE ... ADD COLUMN` covers three different things, distinguished by
what follows the column name.
### A plain column {#plain-column}
```sql
ALTER TABLE t ADD COLUMN c INT
```
Added empty and nullable. Nothing is computed.
### A computed column {#computed-column}
```sql
ALTER TABLE t ADD COLUMN doubled AS value * 2
```
`AS <expression>` declares a [computed column](/feature-engineering/add-computed-column).
The column is committed empty and the expression is stored, not evaluated --
declaring one on a billion-row table costs what declaring one on an empty table
costs. [`REFRESH COLUMN`](/sql/dml/refresh) fills it.
### A function column {#function-column}
```sql
ALTER TABLE t ADD COLUMN embedded AS embed(name) WITH (version = 'fv_1')
```
When the expression calls a [registered function](/sql/ddl/function), the
column is filled by running that function on workers. `version` pins which
immutable function version fills it, so a later registration does not silently
change what the column means.
Several modifiers narrow what gets computed:
| | |
| --- | --- |
| `FILTER (WHERE pred)` | only rows matching `pred` are computed |
| `IGNORE NULLS` | rows with null inputs are skipped |
| `OVER (PARTITION BY col)` | the function sees rows grouped by `col` |
A function returning several values fills several columns at once:
```sql
ALTER TABLE t ADD COLUMN (label, score) AS classify(text) WITH (version = 'fv_1')
```
```sql
ALTER TABLE t ADD COLUMN c AS f(x) FILTER (WHERE keep) WITH (version = 'fv_1')
ALTER TABLE t ADD COLUMN c AS f(x) WITH (num_workers = '2')
```
<Note>
`WITH` on a plain computed column accepts only `version`. Resource options such
as `num_workers` apply to function columns, where there are workers to size.
</Note>
### Table properties {#properties}
```sql
ALTER TABLE t SET UNENFORCED PRIMARY KEY (id)
```
Records which column identifies a row. **Unenforced** is not a hedge in the
naming: uniqueness is not checked on write, and declaring it does not make
duplicates impossible. It tells the planner what to assume.
```sql
ALTER TABLE t SET WAL
ALTER TABLE t SET WAL WITH (sharding = 'bucket', buckets = 4)
ALTER TABLE t SET WAL WITH (maintained_indexes = '')
ALTER TABLE t UNSET WAL
```
A write-ahead log makes small frequent writes cheap by batching them out of the
commit path. `sharding` and `buckets` spread the log so concurrent writers do
not contend on one place; `maintained_indexes` chooses which indexes are kept
current against WAL rows. See
[Background jobs](/maintenance/background-jobs#wal) for how the log gets
folded back into the table.
<Warning>
[`TABLESAMPLE`](/sql/dql/sampling) is refused on a WAL-backed table, because
rows a sample would draw from are not all in the fragments yet.
</Warning>
**Errors and limits**
| | |
| --- | --- |
| `ALTER TABLE ... DROP COLUMN` | not supported |
Dropping, renaming, or retyping a column is an SDK operation --
[`drop_columns`](/management/table#schema) and
[`alter_columns`](/management/table#schema) -- not a SQL statement.
## CLONE {#clone}
```sql
CREATE TABLE docs_snapshot CLONE documents
CREATE TABLE docs_at_v42 CLONE documents AT 42
CREATE TABLE docs_at_release CLONE documents AT TAG 'release-1'
CREATE TABLE docs_yesterday CLONE documents AT TIMESTAMP '2026-09-01T00:00:00Z'
```
A **shallow clone**: the new table shares the source's data files rather than
copying them, so it costs one metadata commit regardless of the source's size.
`AT` pins the point in the source's history to clone. A bare integer is a
version and a bare quoted string is a timestamp; `VERSION`, `TAG` and
`TIMESTAMP` say so explicitly, and a tag always needs its keyword -- a bare
quoted string cannot be both a tag name and a timestamp.
<Warning>
The clone depends on the source's files continuing to exist. If the source is
[compacted](/maintenance/cleanup) past the retention window, the version the
clone points at can be pruned. The SDK's
[`clone_table`](/management/table#rename-clone) also offers a deep clone for
when the copy has to outlive the source's history.
</Warning>
## DROP TABLE {#drop}
```sql
DROP TABLE documents
```
<Warning>
Removes the table and every version of it. There is no undrop.
</Warning>
<Note>
**Enterprise job type:** `drop_table`. See
[Background jobs](/maintenance/background-jobs#teardown).
</Note>
## What to read next {#next}
<CardGroup cols={2}>
<Card title="Table" icon="table" href="/management/table">
The SDK equivalent, and what a table carries.
</Card>
<Card title="Schema evolution" icon="boxes-stacked" href="/management/table#schema">
Renaming, retyping and dropping columns from the SDK.
</Card>
</CardGroup>
+98
View File
@@ -0,0 +1,98 @@
---
title: "View"
sidebarTitle: "View"
description: "CREATE VIEW and DROP VIEW — a saved query, evaluated when read."
icon: eye
keywords: ["create view", "drop view", "sql", "catalog"]
---
<Badge color="red">Enterprise</Badge> [SQL runs on a deployment.](/sql)
A view stores a **query**, not rows. Reading it runs the query against current
data, so a view is never stale -- and never faster than the query it wraps. It
is the counterpart to a [materialized view](/sql/ddl/materialized-view), which
stores rows and is brought up to date by a refresh; both are
[catalog objects](/basics/catalog) defined by a query, differing only in when
that query runs.
There is no SDK method for a view, because the thing it stores *is* a SQL
statement.
## CREATE VIEW {#create}
```sql
CREATE VIEW "recent_matches" AS
SELECT t1.floats
FROM "documents" AS t1
INNER JOIN "categories" AS t2 ON t1.ints = t2.ints
```
The statement returns the view's schema -- column name, data type, nullability
-- resolved from the query at creation time. Anything the
[dialect](/sql/functions) supports can define one: joins, predicates,
aggregates, window functions.
## Reading one {#reading}
A view is queried like a table:
```sql
SELECT * FROM "recent_matches" WHERE floats > 0.5
```
Predicates applied to the view compose with the query inside it rather than
filtering its output afterwards, so a selective filter does not pay for rows
the view would have produced and then discarded.
## DROP VIEW {#drop}
```sql
DROP VIEW "recent_matches"
```
Removes the saved query. Unlike dropping a table, no data is removed -- there
was none to begin with.
## Listing {#listing}
Views and tables share a namespace, and both are things you can query. The
catalog distinguishes them:
| | |
| --- | --- |
| view names | the views in the database |
| table names | the tables |
| relation names | everything queryable -- both |
Use the relation listing when the question is "what can I select from," and the
separate listings when the distinction matters -- before dropping, for
instance, since dropping a view removes only the saved query while dropping a
table removes data.
## Choosing between a view and a materialized view {#choosing}
| | View | Materialized view |
| --- | --- | --- |
| Stores | the query | the rows |
| Freshness | always current | as of the last refresh |
| Read cost | the full query, every read | a table scan |
| Write cost | none | a refresh |
Reach for a **view** when the query is cheap, or when reading stale rows would
be wrong. Reach for a **materialized view** when the query is expensive and the
data changes less often than it is read.
The privileges are separate too: `CREATE_VIEW` and `CREATE_MATERIALIZED_VIEW`
are distinct grants on a namespace, so the ability to create one does not imply
the other. See [Authorization](/governance/authorization).
## What to read next {#next}
<CardGroup cols={2}>
<Card title="Materialized View" icon="table" href="/sql/ddl/materialized-view">
The stored-rows counterpart.
</Card>
<Card title="Management" icon="folder-tree" href="/management">
Where views fit among the other catalog objects.
</Card>
</CardGroup>