cockroachdb / cockroachdb/cockroach
sql: support DDL statements in UDFs
- Dominant language
- Go
- Stars
- 32.5k
- Forks
- 4.1k
- PR merge metrics
- PR metrics pending
Description
**Is your feature request related to a problem?**
We do not allow DDL statements (`CREATE TABLE`, `CREATE SCHEMA`, `CREATE INDEX`, `DROP ...`, etc.) within the body of a user-defined function. Postgres allows these. Attempting it panics with the `unimplemented` error anchored to #110080:
```
unimplemented: CREATE TABLE usage inside a function definition is not supported
```
DDL support in **stored procedures** has now landed (legacy schema changer in v26.3, with declarative schema changer work in flight for 26.4), but the **UDF** half of #110080 was never picked up and is not currently tracked by any dedicated issue:
- #110080 ("support DDL statements in UDFs **and** procedures") is still open and is the only thing covering the UDF case, but in practice it has been treated as the procedures tracker.
- The follow-on epic for 26.4 is titled and scoped "Additional DDL statement support in **stored procedures**" — all of its children (TRUNCATE, CREATE/DROP DATABASE, CTAS, SHOW, CREATE/DROP VIEW/SEQUENCE/TYPE, plus DSC plumbing) are procedure-only.
Filing this so the UDF work isn't lost when #110080 is eventually resolved for procedures.
**Describe the solution you'd like:**
Allow DDL in the body of a UDF, matching the behavior already implemented for stored procedures. Scope should at minimum cover the same statement set supported for procedures, and should address the UDF-specific concerns that don't arise for procedures:
- [ ] Lift the `CanModifySchema` gate in the optbuilder for function bodies (see code reference below)
- [ ] Decide and enforce volatility semantics — a UDF containing DDL cannot be `IMMUTABLE`/`STABLE`; determine whether we reject at `CREATE FUNCTION` time or force `VOLATILE`
- [ ] Define behavior when a DDL-containing UDF is invoked from within a query context (e.g. in a `SELECT` target list or `WHERE` clause), where a schema change mid-statement is not safe
- [ ] Ensure such UDFs are excluded from inlining / normalization paths that assume no side effects
- [ ] Extend the same treatment to trigger functions and `DO` blocks, or explicitly scope them out
- [ ] Logic test and randomized schema-change workload coverage
- [ ] Update the known-limitation doc, which currently covers both UDFs and procedures, once the UDF gap closes
**Describe alternatives you've considered:**
Dynamic SQL is a partial workaround and is being tracked separately — #172439 (dynamic `EXECUTE` in UDFs and DO blocks) combined with #172433 (dynamic DDL/DCL in `EXECUTE`) would let a UDF issue DDL indirectly via a string. That does not cover static DDL written directly in a function body, and it bypasses the planning-time validation we'd want, so it is not a substitute for first-class support.
**Code References:**
The relevant gate is the `default` arm of the statement switch in `Builder.buildStmt`, which panics for anything satisfying `tree.CanModifySchema`:
- [pkg/sql/opt/optbuilder/builder.go](https://github.com/cockroachdb/cockroach/blob/master/pkg/sql/opt/optbuilder/builder.go) — `Builder.buildStmt`, the `unimplemented.NewWithIssuef(110080, ...)` panic
**Additional context:**
@rafiss demonstrated in [a comment on #110080](https://github.com/cockroachdb/cockroach/issues/110080#issuecomment-3074325903) that simply adding `case *tree.CreateTable:` to that switch is enough to get `CREATE TABLE` working inside a PL/pgSQL function:
```sql
CREATE OR REPLACE FUNCTION create_table_example()
RETURNS void AS $$
BEGIN
CREATE TABLE table_example (
id SERIAL PRIMARY KEY,
name TEXT
);
END;
$$ LANGUAGE plpgsql;
```
This suggests the optbuilder gate is shared between procedures and functions and is not itself the hard part — the open questions are the volatility and query-context semantics listed above.
Related:
- #110080 — original tracking issue for DDL in UDFs and procedures
- #172439 — dynamic `EXECUTE` in UDFs and DO blocks
- #172433 — dynamic DDL/DCL in `EXECUTE`
- #172405 — SHOW commands in stored procedures and functions
Jira issue: CRDB-67899
Epic CRDB-65937
Contributor guide
Research direction
Start in pkg/sql/opt/optbuilder/builder.go at Builder.buildStmt and compare the existing stored-procedure DDL handling. Work through volatility, query-context, inlining, trigger-function, and DO-block semantics before defining the supported statement set. Done means validated logic tests and randomized schema-change coverage, with the known-limitation documentation updated.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go, sql
- Domain
- databases
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100