Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
269 changes: 269 additions & 0 deletions demo.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,269 @@
CREATE PROCEDURE foo(x INT) LANGUAGE SQL AS $$
SELECT 1;
SELECT 2;
$$;

EXPLAIN ANALYZE CALL foo(3);


--------------------------------------------------------------------------------
-- EXPLAIN ANALYZE with routines (functions, procedures, triggers).
--
-- Demonstrates how routine body plans, invocation counts, and per-node
-- execution stats surface in EXPLAIN ANALYZE output. The emphasis is on
-- stored procedures (CALL), with UDF and trigger coverage for contrast.
--
-- Run with:
-- ./cockroach demo --empty --no-line-editor < demo.sql
--------------------------------------------------------------------------------

CREATE TABLE t (a INT PRIMARY KEY, b INT, FAMILY (a, b));
INSERT INTO t SELECT i, i*10 FROM generate_series(1, 10) AS g(i);


--------------------------------------------------------------------------------
-- PART 1: STORED PROCEDURES (CALL)
--
-- EXPLAIN ANALYZE CALL shows a `call` node above the procedure's routine
-- body. Each body statement becomes a routine node named `_stmt_<kind>_<n>`
-- (or the callee's name for nested CALLs / UDF references).
--------------------------------------------------------------------------------

-- 1. SQL procedure.
CREATE PROCEDURE bump_sql(x INT) LANGUAGE SQL AS $$
UPDATE t SET b = b + 1 WHERE a = x;
$$;

EXPLAIN ANALYZE CALL bump_sql(1);


-- 2. SQL procedure with an OUT parameter (returns a row).
CREATE PROCEDURE get_b(IN x INT, OUT res INT) LANGUAGE SQL AS $$
SELECT b FROM t WHERE a = x
$$;

EXPLAIN ANALYZE CALL get_b(3, NULL);


-- 3. SQL procedure running a multi-table join. The routine body captures the
-- full plan of a non-trivial statement — the join operator and both input
-- scans appear under the `body stmt`, each with its own execution stats.
CREATE TABLE u (a INT PRIMARY KEY, c INT);
INSERT INTO u SELECT i, i*100 FROM generate_series(1, 10) AS g(i);

CREATE PROCEDURE join_summary(lim INT) LANGUAGE SQL AS $$
SELECT t.a, t.b, u.c
FROM t JOIN u ON t.a = u.a
WHERE t.b > lim
ORDER BY t.a;
$$;

EXPLAIN ANALYZE CALL join_summary(30);


-- 4. PL/pgSQL procedure (no control flow).
CREATE PROCEDURE bump_plpgsql(x INT) LANGUAGE PLpgSQL AS $$
BEGIN
UPDATE t SET b = b + 1 WHERE a = x;
END
$$;

EXPLAIN ANALYZE CALL bump_plpgsql(2);


-- 5. PL/pgSQL procedure with an INOUT parameter.
CREATE PROCEDURE inc(INOUT v INT) LANGUAGE PLpgSQL AS $$
BEGIN
v := v + 1;
END
$$;

EXPLAIN ANALYZE CALL inc(41);


-- 6. Multi-statement DML procedure (INSERT / UPDATE / DELETE). Each body
-- statement becomes its own routine node (`_stmt_exec_1/2/3`), and the
-- mutation operator reports its `actual row count` (3 inserted, 5
-- updated, 3 deleted).
CREATE PROCEDURE dml_proc() LANGUAGE PLpgSQL AS $$
BEGIN
INSERT INTO t VALUES (100, 1000), (101, 1010), (102, 1020);
UPDATE t SET b = b + 1 WHERE a <= 5;
DELETE FROM t WHERE a >= 100;
END
$$;

EXPLAIN ANALYZE CALL dml_proc();


-- 7. Procedure calling another procedure (nested CALL). The callee appears
-- as its own routine node beneath the caller's body.
CREATE PROCEDURE inner_proc(x INT) LANGUAGE SQL AS $$
UPDATE t SET b = b + 1 WHERE a = x;
$$;

CREATE PROCEDURE outer_proc(x INT) LANGUAGE PLpgSQL AS $$
BEGIN
CALL inner_proc(x);
END
$$;

EXPLAIN ANALYZE CALL outer_proc(1);


-- 8. Procedure calling a UDF: the function shows up as a nested routine.
CREATE FUNCTION dbl(x INT) RETURNS INT VOLATILE LANGUAGE SQL AS $$
SELECT x * 2
$$;

CREATE PROCEDURE set_dbl(x INT) LANGUAGE PLpgSQL AS $$
BEGIN
UPDATE t SET b = dbl(x) WHERE a = x;
END
$$;

EXPLAIN ANALYZE CALL set_dbl(1);


-- 9. Procedure with in-body transaction control (COMMIT) — a
-- procedure-only capability with no UDF equivalent.
CREATE PROCEDURE txn_proc() LANGUAGE PLpgSQL AS $$
BEGIN
UPDATE t SET b = b + 1 WHERE a = 1;
COMMIT;
END
$$;

EXPLAIN ANALYZE CALL txn_proc();


-- 10. PL/pgSQL procedure whose body uses control flow (a FOR loop), invoked
-- via CALL. Each control-flow block compiles into a nested sub-routine
-- planned lazily at execution time; under EXPLAIN ANALYZE these appear as
-- their own routine nodes (e.g. `stmt_loop_*`) with per-iteration
-- invocation counts.
CREATE PROCEDURE bump_loop(n INT) LANGUAGE PLpgSQL AS $$
BEGIN
FOR i IN 1..n LOOP
UPDATE t SET b = b + 1 WHERE a = i;
END LOOP;
END
$$;

EXPLAIN ANALYZE CALL bump_loop(3);


-- 11. PL/pgSQL procedure with an IF/ELSE branch, invoked via CALL. The taken
-- branch's body is captured as a nested routine node.
CREATE PROCEDURE classify(x INT) LANGUAGE PLpgSQL AS $$
BEGIN
IF x > 5 THEN UPDATE t SET b = 1 WHERE a = x;
ELSE UPDATE t SET b = 0 WHERE a = x;
END IF;
END
$$;

EXPLAIN ANALYZE CALL classify(7);


--------------------------------------------------------------------------------
-- PART 2: USER-DEFINED FUNCTIONS
--------------------------------------------------------------------------------

-- 12. Scalar SQL UDF in a projection.
-- A single routine node with `invocations` and a `body stmt` subplan.
CREATE FUNCTION lookup_volatile(x INT) RETURNS INT VOLATILE LANGUAGE SQL AS $$
SELECT b FROM t WHERE a = x
$$;

EXPLAIN ANALYZE (VERBOSE) SELECT lookup_volatile(a) FROM t WHERE a <= 3;


-- 13. Nested UDF calls (outer_fn calls inner_fn): body plans nest.
CREATE FUNCTION inner_fn(x INT) RETURNS INT VOLATILE LANGUAGE SQL AS $$
SELECT x * 10
$$;

CREATE FUNCTION outer_fn(x INT) RETURNS INT VOLATILE LANGUAGE SQL AS $$
SELECT inner_fn(x) + 1
$$;

EXPLAIN ANALYZE SELECT outer_fn(a) FROM t WHERE a <= 3;


-- 14. Multiple plan variants for the same routine. NULL vs non-NULL inputs
-- produce different body plans; each is labeled "plan variant: N of M"
-- with its own invocation count.
EXPLAIN ANALYZE
SELECT lookup_volatile(a)
FROM (VALUES (1), (2), (3), (NULL::INT), (NULL::INT)) AS v(a);


-- 15. Set-returning UDF (SETOF) in the FROM clause.
CREATE FUNCTION top_b(lim INT) RETURNS SETOF INT VOLATILE LANGUAGE SQL AS $$
SELECT b FROM t ORDER BY b DESC LIMIT lim
$$;

EXPLAIN ANALYZE SELECT * FROM top_b(3);


-- 16. Volatile UDF in a WHERE filter (invoked once per scanned row).
CREATE FUNCTION is_big(x INT) RETURNS BOOL VOLATILE LANGUAGE SQL AS $$
SELECT x > 50
$$;

EXPLAIN ANALYZE SELECT a FROM t WHERE is_big(b);


-- 17. PL/pgSQL *function* with control flow (a loop) invoked via SELECT. The
-- same control-flow loop works both here (function via SELECT) and in a
-- CALL'd procedure (see examples 10-11): the loop expands into nested
-- routine bodies in the plan.
CREATE FUNCTION sum_to(n INT) RETURNS INT LANGUAGE PLpgSQL AS $$
DECLARE
s INT := 0;
BEGIN
FOR i IN 1..n LOOP
s := s + i;
END LOOP;
RETURN s;
END
$$;

EXPLAIN ANALYZE SELECT sum_to(a) FROM t WHERE a <= 3;


--------------------------------------------------------------------------------
-- PART 3: TRIGGERS
--------------------------------------------------------------------------------

-- 18. AFTER INSERT trigger: the fired trigger function appears under an
-- `after-triggers` node.
CREATE TABLE audit (id INT PRIMARY KEY DEFAULT unique_rowid(), a INT, b INT);

CREATE FUNCTION audit_insert() RETURNS TRIGGER LANGUAGE PLpgSQL AS $$
BEGIN
INSERT INTO audit (a, b) VALUES ((NEW).a, (NEW).b);
RETURN NEW;
END
$$;

CREATE TRIGGER trg_audit AFTER INSERT ON t
FOR EACH ROW EXECUTE FUNCTION audit_insert();

EXPLAIN ANALYZE INSERT INTO t VALUES (100, 1000);


-- 19. BEFORE INSERT trigger that mutates the incoming row: appears under a
-- `before-triggers` node.
CREATE FUNCTION bump_before() RETURNS TRIGGER LANGUAGE PLpgSQL AS $$
BEGIN
NEW.b := (NEW).b + 1;
RETURN NEW;
END
$$;

CREATE TRIGGER trg_bump BEFORE INSERT ON t
FOR EACH ROW EXECUTE FUNCTION bump_before();

EXPLAIN ANALYZE INSERT INTO t VALUES (200, 2000);
2 changes: 1 addition & 1 deletion docs/generated/settings/settings-for-tenants.txt
Original file line number Diff line number Diff line change
Expand Up @@ -446,4 +446,4 @@ trace.zipkin.collector string the address of a Zipkin instance to receive trace
ui.database_locality_metadata.enabled boolean true if enabled shows extended locality data about databases and tables in DB Console which can be expensive to compute application
ui.default_timezone string the default timezone used to format timestamps in the ui application
ui.display_timezone enumeration etc/utc the timezone used to format timestamps in the ui. This setting is deprecatedand will be removed in a future version. Use the 'ui.default_timezone' setting instead. 'ui.default_timezone' takes precedence over this setting. [etc/utc = 0, america/new_york = 1] application
version version 1000026.2-upgrading-to-1000026.3-step-010 set the active cluster version in the format '<major>.<minor>' application
version version 1000026.2-upgrading-to-1000026.3-step-012 set the active cluster version in the format '<major>.<minor>' application
2 changes: 1 addition & 1 deletion docs/generated/settings/settings.html
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,6 @@
<tr><td><div id="setting-ui-database-locality-metadata-enabled" class="anchored"><code>ui.database_locality_metadata.enabled</code></div></td><td>boolean</td><td><code>true</code></td><td>if enabled shows extended locality data about databases and tables in DB Console which can be expensive to compute</td><td>Basic/Standard/Advanced/Self-Hosted</td></tr>
<tr><td><div id="setting-ui-default-timezone" class="anchored"><code>ui.default_timezone</code></div></td><td>string</td><td><code></code></td><td>the default timezone used to format timestamps in the ui</td><td>Basic/Standard/Advanced/Self-Hosted</td></tr>
<tr><td><div id="setting-ui-display-timezone" class="anchored"><code>ui.display_timezone</code></div></td><td>enumeration</td><td><code>etc/utc</code></td><td>the timezone used to format timestamps in the ui. This setting is deprecatedand will be removed in a future version. Use the &#39;ui.default_timezone&#39; setting instead. &#39;ui.default_timezone&#39; takes precedence over this setting. [etc/utc = 0, america/new_york = 1]</td><td>Basic/Standard/Advanced/Self-Hosted</td></tr>
<tr><td><div id="setting-version" class="anchored"><code>version</code></div></td><td>version</td><td><code>1000026.2-upgrading-to-1000026.3-step-010</code></td><td>set the active cluster version in the format &#39;&lt;major&gt;.&lt;minor&gt;&#39;</td><td>Basic/Standard/Advanced/Self-Hosted</td></tr>
<tr><td><div id="setting-version" class="anchored"><code>version</code></div></td><td>version</td><td><code>1000026.2-upgrading-to-1000026.3-step-012</code></td><td>set the active cluster version in the format &#39;&lt;major&gt;.&lt;minor&gt;&#39;</td><td>Basic/Standard/Advanced/Self-Hosted</td></tr>
</tbody>
</table>

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading