Skip to content
Merged
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
430 changes: 430 additions & 0 deletions docs/generated/metrics/metrics.yaml

Large diffs are not rendered by default.

20 changes: 20 additions & 0 deletions pkg/internal/metricscan/metric_owners.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1059,10 +1059,30 @@ owners:
sql_restart_savepoint_rollback_started_count: cockroachdb/sql-queries
sql_restart_savepoint_started_count: cockroachdb/sql-queries
sql_rls_policies_applied_count: cockroachdb/sql-queries
sql_routine_alter_default_privileges_count: cockroachdb/sql-queries
sql_routine_alter_default_privileges_started_count: cockroachdb/sql-queries
sql_routine_create_role_count: cockroachdb/sql-queries
sql_routine_create_role_started_count: cockroachdb/sql-queries
sql_routine_create_schema_count: cockroachdb/sql-queries
sql_routine_create_schema_started_count: cockroachdb/sql-queries
sql_routine_create_table_count: cockroachdb/sql-queries
sql_routine_create_table_started_count: cockroachdb/sql-queries
sql_routine_create_temp_table_count: cockroachdb/sql-queries
sql_routine_create_temp_table_started_count: cockroachdb/sql-queries
sql_routine_delete_count: cockroachdb/sql-queries
sql_routine_delete_started_count: cockroachdb/sql-queries
sql_routine_drop_role_count: cockroachdb/sql-queries
sql_routine_drop_role_started_count: cockroachdb/sql-queries
sql_routine_drop_schema_count: cockroachdb/sql-queries
sql_routine_drop_schema_started_count: cockroachdb/sql-queries
sql_routine_drop_table_count: cockroachdb/sql-queries
sql_routine_drop_table_started_count: cockroachdb/sql-queries
sql_routine_grant_count: cockroachdb/sql-queries
sql_routine_grant_started_count: cockroachdb/sql-queries
sql_routine_insert_count: cockroachdb/sql-queries
sql_routine_insert_started_count: cockroachdb/sql-queries
sql_routine_revoke_count: cockroachdb/sql-queries
sql_routine_revoke_started_count: cockroachdb/sql-queries
sql_routine_select_count: cockroachdb/sql-queries
sql_routine_select_started_count: cockroachdb/sql-queries
sql_routine_update_count: cockroachdb/sql-queries
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2606,14 +2606,54 @@ sql_restart_savepoint_started_count: sql.restart_savepoint.started.count
sql_restart_savepoint_started_count_internal: sql.restart_savepoint.started.internal
sql_rls_policies_applied_count: sql.rls.policies_applied.count
sql_rls_policies_applied_count_internal: sql.rls.policies_applied.count.internal
sql_routine_alter_default_privileges_count: sql.routine.alter_default_privileges.count
sql_routine_alter_default_privileges_count_internal: sql.routine.alter_default_privileges.count.internal
sql_routine_alter_default_privileges_started_count: sql.routine.alter_default_privileges.started.count
sql_routine_alter_default_privileges_started_count_internal: sql.routine.alter_default_privileges.started.count.internal
sql_routine_create_role_count: sql.routine.create_role.count
sql_routine_create_role_count_internal: sql.routine.create_role.count.internal
sql_routine_create_role_started_count: sql.routine.create_role.started.count
sql_routine_create_role_started_count_internal: sql.routine.create_role.started.count.internal
sql_routine_create_schema_count: sql.routine.create_schema.count
sql_routine_create_schema_count_internal: sql.routine.create_schema.count.internal
sql_routine_create_schema_started_count: sql.routine.create_schema.started.count
sql_routine_create_schema_started_count_internal: sql.routine.create_schema.started.count.internal
sql_routine_create_table_count: sql.routine.create_table.count
sql_routine_create_table_count_internal: sql.routine.create_table.count.internal
sql_routine_create_table_started_count: sql.routine.create_table.started.count
sql_routine_create_table_started_count_internal: sql.routine.create_table.started.count.internal
sql_routine_create_temp_table_count: sql.routine.create_temp_table.count
sql_routine_create_temp_table_count_internal: sql.routine.create_temp_table.count.internal
sql_routine_create_temp_table_started_count: sql.routine.create_temp_table.started.count
sql_routine_create_temp_table_started_count_internal: sql.routine.create_temp_table.started.count.internal
sql_routine_delete_count: sql.routine.delete.count
sql_routine_delete_count_internal: sql.routine.delete.count.internal
sql_routine_delete_started_count: sql.routine.delete.started.count
sql_routine_delete_started_count_internal: sql.routine.delete.started.count.internal
sql_routine_drop_role_count: sql.routine.drop_role.count
sql_routine_drop_role_count_internal: sql.routine.drop_role.count.internal
sql_routine_drop_role_started_count: sql.routine.drop_role.started.count
sql_routine_drop_role_started_count_internal: sql.routine.drop_role.started.count.internal
sql_routine_drop_schema_count: sql.routine.drop_schema.count
sql_routine_drop_schema_count_internal: sql.routine.drop_schema.count.internal
sql_routine_drop_schema_started_count: sql.routine.drop_schema.started.count
sql_routine_drop_schema_started_count_internal: sql.routine.drop_schema.started.count.internal
sql_routine_drop_table_count: sql.routine.drop_table.count
sql_routine_drop_table_count_internal: sql.routine.drop_table.count.internal
sql_routine_drop_table_started_count: sql.routine.drop_table.started.count
sql_routine_drop_table_started_count_internal: sql.routine.drop_table.started.count.internal
sql_routine_grant_count: sql.routine.grant.count
sql_routine_grant_count_internal: sql.routine.grant.count.internal
sql_routine_grant_started_count: sql.routine.grant.started.count
sql_routine_grant_started_count_internal: sql.routine.grant.started.count.internal
sql_routine_insert_count: sql.routine.insert.count
sql_routine_insert_count_internal: sql.routine.insert.count.internal
sql_routine_insert_started_count: sql.routine.insert.started.count
sql_routine_insert_started_count_internal: sql.routine.insert.started.count.internal
sql_routine_revoke_count: sql.routine.revoke.count
sql_routine_revoke_count_internal: sql.routine.revoke.count.internal
sql_routine_revoke_started_count: sql.routine.revoke.started.count
sql_routine_revoke_started_count_internal: sql.routine.revoke.started.count.internal
sql_routine_select_count: sql.routine.select.count
sql_routine_select_count_internal: sql.routine.select.count.internal
sql_routine_select_started_count: sql.routine.select.started.count
Expand Down
142 changes: 142 additions & 0 deletions pkg/server/application_api/metrics_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,17 @@ func confirmMetricCount(t *testing.T, db *gosql.DB, metricName string, expected
require.Equal(t, expected, int(res.Int64))
}

// confirmRoutineMetricCounts asserts the started and completed routine
// counters for the given dotted suffix (e.g. "create_table" maps to
// sql.routine.create_table.started.count and sql.routine.create_table.count).
func confirmRoutineMetricCounts(
t *testing.T, db *gosql.DB, suffix string, expectedStarted, expectedExecuted int,
) {
t.Helper()
confirmMetricCount(t, db, fmt.Sprintf("sql.routine.%s.started.count", suffix), expectedStarted)
confirmMetricCount(t, db, fmt.Sprintf("sql.routine.%s.count", suffix), expectedExecuted)
}

func TestStoreProcedureCallStatementMetrics(t *testing.T) {
defer leaktest.AfterTest(t)()
defer log.Scope(t).Close(t)
Expand Down Expand Up @@ -786,3 +797,134 @@ func TestUDFStatementMetrics(t *testing.T) {
confirmMetricCount(t, db, "sql.routine.insert.count", expectedInsertCount)
confirmMetricCount(t, db, "sql.routine.select.count", expectedSelectCount)
}

// TestStoreProcedureCallDDLDCLMetrics verifies that DDL and DCL statements
// executed inside stored procedure bodies advance the corresponding
// sql.routine.<type>.{started.count,count} counters.
func TestStoreProcedureCallDDLDCLMetrics(t *testing.T) {
defer leaktest.AfterTest(t)()
defer log.Scope(t).Close(t)
srv := serverutils.StartServerOnly(t, base.TestServerArgs{})
defer srv.Stopper().Stop(context.Background())
db := srv.SystemLayer().SQLConn(t)

// DDL inside PL/pgSQL procedure bodies is only permitted when late
// binding is enabled, so turn it on before creating those procedures.
_, err := db.Exec(
`SET CLUSTER SETTING sql.procedures.plpgsql.late_binding.enabled = true`,
)
require.NoError(t, err)

// Pre-create everything later procedures reference. Doing it at the
// top level keeps the routine counters at zero before the per-case
// CALLs below run.
_, err = db.Exec(`
CREATE TABLE base_tbl (a INT PRIMARY KEY);
CREATE TABLE drop_target_tbl (a INT PRIMARY KEY);
CREATE SCHEMA drop_target_schema;
CREATE ROLE drop_target_role;
CREATE ROLE grantee_role;
SET experimental_enable_temp_tables = 'on';
`)
require.NoError(t, err)

// callProc creates a single-statement procedure named p_<suffix>
// with the given body and calls it.
callProc := func(t *testing.T, suffix, body string) {
t.Helper()
_, err := db.Exec(fmt.Sprintf(
`CREATE PROCEDURE p_%[1]s() LANGUAGE PLpgSQL AS $$ BEGIN %[2]s; END $$; CALL p_%[1]s();`,
suffix, body,
))
require.NoError(t, err)
}

// Each row exercises one routine body statement and asserts both
// the started and executed counters advance by 1.
for _, tc := range []struct{ suffix, body string }{
{"create_table", "CREATE TABLE proc_created_tbl (a INT PRIMARY KEY)"},
{"drop_table", "DROP TABLE drop_target_tbl"},
{"create_temp_table", "CREATE TEMPORARY TABLE proc_temp_tbl (a INT PRIMARY KEY)"},
{"create_schema", "CREATE SCHEMA proc_created_schema"},
{"drop_schema", "DROP SCHEMA drop_target_schema"},
{"create_role", "CREATE ROLE proc_created_role"},
{"drop_role", "DROP ROLE drop_target_role"},
} {
t.Run(tc.suffix, func(t *testing.T) {
callProc(t, tc.suffix, tc.body)
confirmRoutineMetricCounts(t, db, tc.suffix, 1, 1)
})
}
// CREATE TEMPORARY TABLE shares the CREATE TABLE tag but must not
// advance the permanent counter.
confirmRoutineMetricCounts(t, db, "create_table", 1, 1)

t.Run("failed_create_table", func(t *testing.T) {
// base_tbl already exists, so a non-IF-NOT-EXISTS CREATE fails;
// only the started counter must advance.
_, err := db.Exec(`
CREATE PROCEDURE p_create_table_dup() LANGUAGE PLpgSQL AS $$
BEGIN CREATE TABLE base_tbl (a INT PRIMARY KEY); END $$;
`)
require.NoError(t, err)
_, err = db.Exec(`CALL p_create_table_dup();`)
require.Error(t, err)
confirmRoutineMetricCounts(t, db, "create_table", 2, 1)
})

t.Run("multi_dcl", func(t *testing.T) {
// Verify each body statement is counted individually.
_, err := db.Exec(`
CREATE PROCEDURE p_multi_dcl() LANGUAGE PLpgSQL AS $$
BEGIN
GRANT SELECT ON base_tbl TO grantee_role;
GRANT INSERT ON base_tbl TO grantee_role;
REVOKE SELECT ON base_tbl FROM grantee_role;
GRANT UPDATE ON base_tbl TO grantee_role;
REVOKE INSERT ON base_tbl FROM grantee_role;
ALTER DEFAULT PRIVILEGES GRANT SELECT ON TABLES TO grantee_role;
ALTER DEFAULT PRIVILEGES REVOKE SELECT ON TABLES FROM grantee_role;
END $$;
CALL p_multi_dcl();
`)
require.NoError(t, err)
confirmRoutineMetricCounts(t, db, "grant", 3, 3)
confirmRoutineMetricCounts(t, db, "revoke", 2, 2)
confirmRoutineMetricCounts(t, db, "alter_default_privileges", 2, 2)
})

t.Run("language_sql", func(t *testing.T) {
// Verify counters also advance for LANGUAGE SQL procedure bodies,
// not just PLpgSQL.
_, err := db.Exec(`
CREATE PROCEDURE p_sqllang_grant() LANGUAGE SQL AS $$
GRANT DELETE ON base_tbl TO grantee_role;
$$;
CALL p_sqllang_grant();
`)
require.NoError(t, err)
confirmRoutineMetricCounts(t, db, "grant", 4, 4)
})

t.Run("nested_call", func(t *testing.T) {
// The inner body statement must attribute to its per-tag
// counter, not just bump an outer-procedure counter.
_, err := db.Exec(`
CREATE PROCEDURE p_inner_create() LANGUAGE PLpgSQL AS $$
BEGIN CREATE TABLE nested_created_tbl (a INT PRIMARY KEY); END $$;
CREATE PROCEDURE p_outer_nested() LANGUAGE PLpgSQL AS $$
BEGIN CALL p_inner_create(); END $$;
CALL p_outer_nested();
`)
require.NoError(t, err)
// Prior subtests bumped started by 2 (1 success + 1 failure)
// and executed by 1; the inner CREATE TABLE here adds 1 to each.
confirmRoutineMetricCounts(t, db, "create_table", 3, 2)
})

// Routine DML counters must stay at 0 since no DML ran in any
// procedure body above.
for _, suffix := range []string{"select", "insert", "update", "delete"} {
confirmMetricCount(t, db, fmt.Sprintf("sql.routine.%s.count", suffix), 0)
}
}
72 changes: 68 additions & 4 deletions pkg/sql/conn_executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -4949,6 +4949,20 @@ type StatementCounters struct {
RoutineInsertCount telemetry.CounterWithAggMetric
RoutineDeleteCount telemetry.CounterWithAggMetric

// DDL/DCL statements within the UDF/SP body. CREATE TABLE is split
// by tree.Persistence: RoutineCreateTableCount tracks permanent
// tables and RoutineCreateTempTableCount tracks temporary tables.
RoutineCreateTableCount telemetry.CounterWithAggMetric
RoutineCreateTempTableCount telemetry.CounterWithAggMetric
RoutineDropTableCount telemetry.CounterWithAggMetric
RoutineCreateSchemaCount telemetry.CounterWithAggMetric
RoutineDropSchemaCount telemetry.CounterWithAggMetric
RoutineCreateRoleCount telemetry.CounterWithAggMetric
RoutineDropRoleCount telemetry.CounterWithAggMetric
RoutineGrantCount telemetry.CounterWithAggMetric
RoutineRevokeCount telemetry.CounterWithAggMetric
RoutineAlterDefaultPrivilegesCount telemetry.CounterWithAggMetric

// Transaction operations.
TxnBeginCount telemetry.CounterWithAggMetric
TxnCommitCount telemetry.CounterWithAggMetric
Expand Down Expand Up @@ -5035,6 +5049,26 @@ func makeStartedStatementCounters(internal bool) StatementCounters {
getMetricMeta(MetaRoutineInsertStarted, internal)),
RoutineDeleteCount: telemetry.NewCounterWithAggMetric(
getMetricMeta(MetaRoutineDeleteStarted, internal)),
RoutineCreateTableCount: telemetry.NewCounterWithAggMetric(
getMetricMeta(MetaRoutineCreateTableStarted, internal)),
RoutineCreateTempTableCount: telemetry.NewCounterWithAggMetric(
getMetricMeta(MetaRoutineCreateTempTableStarted, internal)),
RoutineDropTableCount: telemetry.NewCounterWithAggMetric(
getMetricMeta(MetaRoutineDropTableStarted, internal)),
RoutineCreateSchemaCount: telemetry.NewCounterWithAggMetric(
getMetricMeta(MetaRoutineCreateSchemaStarted, internal)),
RoutineDropSchemaCount: telemetry.NewCounterWithAggMetric(
getMetricMeta(MetaRoutineDropSchemaStarted, internal)),
RoutineCreateRoleCount: telemetry.NewCounterWithAggMetric(
getMetricMeta(MetaRoutineCreateRoleStarted, internal)),
RoutineDropRoleCount: telemetry.NewCounterWithAggMetric(
getMetricMeta(MetaRoutineDropRoleStarted, internal)),
RoutineGrantCount: telemetry.NewCounterWithAggMetric(
getMetricMeta(MetaRoutineGrantStarted, internal)),
RoutineRevokeCount: telemetry.NewCounterWithAggMetric(
getMetricMeta(MetaRoutineRevokeStarted, internal)),
RoutineAlterDefaultPrivilegesCount: telemetry.NewCounterWithAggMetric(
getMetricMeta(MetaRoutineAlterDefaultPrivilegesStarted, internal)),
CRUDQueryCount: telemetry.NewCounterWithAggMetric(
getMetricMeta(MetaCRUDStarted, internal)),
DdlCount: telemetry.NewCounterWithMetric(
Expand Down Expand Up @@ -5096,6 +5130,26 @@ func makeExecutedStatementCounters(internal bool) StatementCounters {
getMetricMeta(MetaRoutineInsertExecuted, internal)),
RoutineDeleteCount: telemetry.NewCounterWithAggMetric(
getMetricMeta(MetaRoutineDeleteExecuted, internal)),
RoutineCreateTableCount: telemetry.NewCounterWithAggMetric(
getMetricMeta(MetaRoutineCreateTableExecuted, internal)),
RoutineCreateTempTableCount: telemetry.NewCounterWithAggMetric(
getMetricMeta(MetaRoutineCreateTempTableExecuted, internal)),
RoutineDropTableCount: telemetry.NewCounterWithAggMetric(
getMetricMeta(MetaRoutineDropTableExecuted, internal)),
RoutineCreateSchemaCount: telemetry.NewCounterWithAggMetric(
getMetricMeta(MetaRoutineCreateSchemaExecuted, internal)),
RoutineDropSchemaCount: telemetry.NewCounterWithAggMetric(
getMetricMeta(MetaRoutineDropSchemaExecuted, internal)),
RoutineCreateRoleCount: telemetry.NewCounterWithAggMetric(
getMetricMeta(MetaRoutineCreateRoleExecuted, internal)),
RoutineDropRoleCount: telemetry.NewCounterWithAggMetric(
getMetricMeta(MetaRoutineDropRoleExecuted, internal)),
RoutineGrantCount: telemetry.NewCounterWithAggMetric(
getMetricMeta(MetaRoutineGrantExecuted, internal)),
RoutineRevokeCount: telemetry.NewCounterWithAggMetric(
getMetricMeta(MetaRoutineRevokeExecuted, internal)),
RoutineAlterDefaultPrivilegesCount: telemetry.NewCounterWithAggMetric(
getMetricMeta(MetaRoutineAlterDefaultPrivilegesExecuted, internal)),
CRUDQueryCount: telemetry.NewCounterWithAggMetric(
getMetricMeta(MetaCRUDExecuted, internal)),
DdlCount: telemetry.NewCounterWithMetric(
Expand Down Expand Up @@ -5187,10 +5241,20 @@ func (sc *StatementCounters) incrementCount(ex *connExecutor, stmt tree.Statemen
// import cycle.
func (sc *StatementCounters) toRoutineStmtCounters() eval.RoutineStatementCounters {
return eval.RoutineStatementCounters{
SelectCount: &sc.RoutineSelectCount,
UpdateCount: &sc.RoutineUpdateCount,
InsertCount: &sc.RoutineInsertCount,
DeleteCount: &sc.RoutineDeleteCount,
SelectCount: &sc.RoutineSelectCount,
UpdateCount: &sc.RoutineUpdateCount,
InsertCount: &sc.RoutineInsertCount,
DeleteCount: &sc.RoutineDeleteCount,
CreateTableCount: &sc.RoutineCreateTableCount,
CreateTempTableCount: &sc.RoutineCreateTempTableCount,
DropTableCount: &sc.RoutineDropTableCount,
CreateSchemaCount: &sc.RoutineCreateSchemaCount,
DropSchemaCount: &sc.RoutineDropSchemaCount,
CreateRoleCount: &sc.RoutineCreateRoleCount,
DropRoleCount: &sc.RoutineDropRoleCount,
GrantCount: &sc.RoutineGrantCount,
RevokeCount: &sc.RoutineRevokeCount,
AlterDefaultPrivilegesCount: &sc.RoutineAlterDefaultPrivilegesCount,
}
}

Expand Down
Loading
Loading