Skip to content

SQL functions & DoActions ​

KarhutlaSQL adds karhutla_* table functions to DuckDB for monitoring, compliance, and operations, plus Flight DoAction commands for automation. These functions never need table privileges; what they return depends on the caller's role, as noted below. Queries that call only these functions (no tables) skip the resource-group queue and quotas, so an admin can always inspect and kill sessions on a busy server.

Table functions ​

Sessions & monitoring ​

FunctionReturnsWho
karhutla_sessions()session_id, user, source, peer, started_at, last_active_at, active_statements, statement, statement_started_at, rows_sent, bytes_sent, currentadmin: all sessions; others: their own
karhutla_kill_session(session_id)session_id, killed — cancels the session's statements and revokes its token on every instanceadmin (call with CALL or SELECT * FROM)
karhutla_query_history()request_id, session_id, user, kind, resource_group, statement, status, error, started_at, queue_ms, duration_ms, rows, bytes, peak_memory_bytes, plan_hash — last 10,000 statements in memoryadmin: all; others: their own
karhutla_metrics()name, labels, type, value — the Prometheus metrics as rowsall authenticated users
karhutla_chargeback()team, window_start, queries, exec_seconds, rows, bytes, total_queries, total_exec_seconds, total_rows, total_bytesadmin: all teams; others: their team

statement holds sha256:<hex> unless the server runs with --audit-log-sql. peak_memory_bytes and plan_hash need --query-profiling. See Monitoring.

Compliance ​

FunctionReturnsWho
karhutla_access_history()Per-column access records for the last 7 days: ts, request_id, session_id, user, source, kind, action, status, rows, table_name, column_name, tag, policy, row_filter, sql_sha256, rewritten_sql_sha256, sqladmin: all; others: their own
karhutla_access_history_range(from_date, to_date)Same columns for a UTC date range (inclusive)admin: all; others: their own
karhutla_report_run(name)Runs a report from reports.yaml: report_id, name, snapshot_id, rows, location, result_sha256, manifest_sha256roles listed on the report
karhutla_report_run_at(name, as_of)Same, on a past DuckLake snapshot; as_of is a version number or an RFC 3339 timeroles listed on the report
karhutla_dq_results()Great Expectations validation summaries: table_name, suite, run_id, validation_id, snapshot_id, success, evaluated, failed_critical, failed_warning, validated_at, run_by, resultsall authenticated users (no row values)
karhutla_classify_scan()Suggested PII tags for untagged columns: table_name, column_name, data_type, suggested_tag, match_ratio, sampled, reason, current_tag — no valuesadmin

Access history needs an archive (--archive-s3-* or --archive-dir). See Monitoring, Reports, Data quality, auto-classification.

Scheduled jobs ​

FunctionReturnsWho
karhutla_jobs()name, kind, target, schedule, next_run, running, last_start, last_end, last_status, last_error, last_rowsadmin
karhutla_run_job(name)name, started — runs the job now (asynchronously)admin

See Scheduled jobs.

AI & semantic layer ​

FunctionReturnsWho
karhutla_verified_queries()name, question, sql, verified_by, verified_at from --verified-queries-fileall authenticated users
karhutla_semantic_model()semantic_model (YAML text)all authenticated users

See MCP server.

Examples ​

sql
-- Who is connected, and what are they running?
SELECT user, peer, active_statements, statement FROM karhutla_sessions();

-- Kill a runaway session (admin)
CALL karhutla_kill_session('6c9c5ed1-2467-49e7-beaf-6a4cd9b3a19e');

-- Slow statements in the last hour
SELECT user, duration_ms, queue_ms, rows, statement
FROM karhutla_query_history()
WHERE started_at > now() - INTERVAL 1 HOUR AND duration_ms > 1000
ORDER BY duration_ms DESC;

-- Who read the NIK column this month, and was it masked?
SELECT ts, user, policy, row_filter
FROM karhutla_access_history_range(DATE '2026-10-01', DATE '2026-10-31')
WHERE table_name = 'demo.main.nasabah' AND column_name = 'nik';

-- Run a signed report
CALL karhutla_report_run('balance_per_branch');

Flight DoActions ​

DoAction takes a JSON body and returns JSON. Use any Flight client, for example PyArrow:

python
import json, pyarrow.flight as fl
c = fl.FlightClient("grpc+tls://host:31337")
opts = fl.FlightCallOptions(headers=[c.authenticate_basic_token("admin", password)])
res = c.do_action(fl.Action("list_sessions", b""), opts)
print(json.loads(next(res).body.to_pybytes()))
ActionBody → resultWho
health— → statusall authenticated users
list_sessions— → sessionsadmin
kill_session{"session_id"}admin
policy_status— → active and pending policy/classificationadmin
reload_policy{"document": "policy" | "classification"} → pending change, counts as first approvaladmin
approve_policy{"document", "hash"} → second approval activates itadmin (a different admin)
backup— → backup manifestadmin
refresh_table{"table", "sql"} → {"table", "rows"} — atomic CREATE OR REPLACE TABLE … AS SELECTwrite on the table + read on the sources
dq_snapshot{"table"} → {"table", "snapshot_id"}dq_runner role + read on the table
dq_publish{"table", "snapshot_id", "result": <GX Validation Result>}dq_runner role + read on the table
audit.pii_access{"subject_id", "from", "to"} → statements that may have read the subject's datadpo role or admin

Admin HTTP endpoints ​

On --metrics-port (default 9090). /healthz and /metrics are open; the /admin/* endpoints need Authorization: Bearer <token> of an admin.

Method & pathPurpose
GET /healthzLiveness/readiness (runs --health-check-query)
GET /metricsPrometheus metrics
GET /admin/sessionsList sessions
DELETE /admin/sessions/{id}Kill a session
GET /admin/access-history?since=&until=&user=&table=&column=NDJSON export for data-subject requests
GET /admin/policyPolicy status
POST /admin/policy/{document}/reloadPropose a policy/classification change
POST /admin/policy/{document}/approve?hash=Approve a pending change

Error codes ​

gRPC codeTypical cause
UNAUTHENTICATEDMissing/invalid credentials, expired or killed token
PERMISSION_DENIEDMissing privilege, identity not in allow-list, SQL that cannot be governed
RESOURCE_EXHAUSTEDQueue full or timed out, rate limit, quota exceeded, max_bytes exceeded
DEADLINE_EXCEEDEDQuery timeout
CANCELLEDSession killed or client cancelled
FAILED_PRECONDITIONReport gate failed (assert / DQ), data changed during DQ validation, unknown snapshot
UNAVAILABLEArchive unreachable for too long (fail-closed), partial kill propagation
INVALID_ARGUMENTMalformed DoAction body or GX payload

Released under the Apache 2.0 License.