CSharpDB v3.6.0
v3.6.0
v3.6.0 adds trusted, in-process C# scalar functions and commands across
CSharpDB's user-facing expression and automation surfaces. Host applications
can now register C# callbacks when opening or hosting a database, then call
those callbacks from SQL, SQL-backed triggers and procedures, Admin Forms
formulas/events/actions, Admin Reports calculated text and preview lifecycle
events, and pipeline filter/derive/hook expressions.
The release also adds tableless scalar SELECT support, common built-in scalar
functions, Admin callback catalog metadata, SQL autocomplete for built-ins and
tableless-safe host callbacks, and local Admin artifact cleanup to keep
incremental builds fast.
Trusted C# Scalar Functions
- Added the shared
DbFunctionRegistry,DbFunctionRegistryBuilder,
DbScalarFunctionDelegate, andDbScalarFunctionOptionspublic model in
CSharpDB.Primitives. - Added
DatabaseOptions.FunctionsplusConfigureFunctions(...)so embedded
hosts can register scalar functions when opening file-backed, in-memory, or
hybrid databases. - SQL expression evaluation now resolves registered scalar functions in
projections, filters, ordering expressions,INSERT/UPDATEexpressions,
trigger bodies, and stored SQL procedure bodies. - Direct clients can pass trusted functions through
DirectDatabaseOptions;
HTTP and gRPC clients still do not serialize delegates and can only call
functions registered inside the remote host process. - Admin Forms formulas and Admin Reports calculated expressions can use the
same registry while preserving existing arithmetic and aggregate behavior. - Pipeline filter and derived-column expressions can call registered functions;
package definitions store expressions plus generated automation metadata, but
never C# function bodies. - Scalar callback registration now carries
CanRunWithoutFrommetadata so
hosts can identify functions that are safe to discover in tableless
SELECT ...contexts. - Added the usage guide at
docs/trusted-csharp-functions/README.md.
Tableless SELECT And Built-In Scalar Functions
- SQL now supports scalar
SELECTstatements without aFROMclause through a
single-row planner source. - Tableless statements such as
SELECT Date();,SELECT abs(1123.34);, and
SELECT Slugify('Hello World');can execute without inventing a dummy table
when the expression does not need row context. - Added a central built-in scalar dispatcher for common text, date/time,
numeric, conversion, and null helpers, including functions such asABS,
DATE,DATESERIAL,DATEADD,DATEDIFF,LEN,UCASE,LCASE,
ROUND,IFNULL, andNZ. - Query planning now infers built-in scalar return types where possible.
- Query paging and Admin result serialization now handle the internal
tableless single-row source. - BLOB procedure parameters can now round-trip through tableless
SELECT @payload;rather than failing on the old unsupported-path
assumption.
Admin Callback Catalog And Formula UX
- The Admin navigation now groups callbacks under
Callbacks / Internaland
Callbacks / External. - Internal callbacks show built-in formula functions separately from registered
host callbacks, so the list remains navigable as the built-in surface grows. - External callbacks show host-registered/user-created callbacks such as sample
functions and automation commands. - Callback details now surface whether a scalar callback is marked for
tablelessSELECT. - SQL editor completion now suggests built-in scalar functions and host
callbacks marked withCanRunWithoutFrom. - Admin Forms formulas now have an Access-style function catalog/helper and
domain-function support for common form expressions.
Trusted Commands And Form Events
- Added the shared
DbCommandRegistry,DbCommandRegistryBuilder,
DbCommandDelegate,DbCommandContext,DbCommandResult, and
DbCommandOptionspublic model inCSharpDB.Primitives. DbCommandOptionsnow includesTimeoutandIsLongRunning, and
DbCommandRegistryBuilder.AddAsyncCommand(...)registersTask-based host
callbacks without manualValueTaskwrapping.- Command timeouts cancel the command invocation token and surface as command
failures through the existing Forms, Reports, and Pipelines dispatch paths;
external cancellation is still propagated as cancellation. - Admin Forms can now store form-level event bindings that reference trusted
command names instead of storing C# source. - The Forms data-entry runtime dispatches
OnOpen,OnLoad,BeforeInsert,
AfterInsert,BeforeUpdate,AfterUpdate,BeforeDelete, and
AfterDelete. BeforeInsert,BeforeUpdate, andBeforeDeletecan cancel the requested
write by returningDbCommandResult.Failure(...); after-events report errors
without attempting to roll back a completed write.- Command context arguments include current record fields converted to
DbValue; metadata includes the Forms surface, form id/name, table name, and
event name. AddCSharpDbAdminForms(...)now has a command-registration overload for
trusted host applications.- The Admin Forms designer preserves and edits form-level event bindings
instead of dropping automation metadata during save. - Added a command button control that invokes a trusted host command on click,
passing current record fields, optional configured arguments, and form
metadata to the command callback. - Added control-level Admin Forms event bindings for
OnClick,OnChange,
OnGotFocus, andOnLostFocus, so ordinary controls can invoke trusted
host commands without being command buttons. - The Forms property inspector now edits selected-control event bindings using
the same registered-command picker and JSON argument editor as form-level
events. - Added shared declarative action sequence metadata with
RunCommand,
SetFieldValue,ShowMessage, andStopsteps for Admin Forms automation.
Form and control event bindings can now be command-only,
action-sequence-only, or a command followed by an action sequence. - Added built-in rendered-form actions for
NewRecord,SaveRecord,
DeleteRecord,RefreshRecords,PreviousRecord,NextRecord, and
GoToRecord, so command buttons and control events can drive common form
workflows without host C# callbacks. - Action sequence steps can now include a simple condition such as
Status = 'Ready',Amount > 0, orIsActive; false conditions skip that
step, while malformed conditions fail through the normal step failure path. - Forms can now store reusable named action sequences on
FormDefinitionand
invoke them from event/button sequences withRunActionSequence, including
optional per-call arguments and a nesting guard for recursive loops. - The form-event and selected-control event editors now include a visual
action-sequence editor for adding, ordering, removing, and configuring
command, reusable sequence, field, message, stop, built-in record actions,
and per-step conditions. - The Forms property inspector now includes a reusable action-sequence library
editor at the form level, and event action editors can pick those named
sequences while preserving missing names for portable metadata. - The action-sequence editor uses registered-command pickers when commands are
available, preserves missing command names for portable form metadata, and
keeps JSON editing limited to optional argument payloads. - Action sequences store names, arguments, field targets, and literal values
only. They do not store C# source, serialize delegates, or run untrusted code. - Added shared command argument conversion helpers so Forms, Reports, and
Pipelines pass host command arguments with the sameDbValueconversion
rules. - Admin Reports can now bind
OnOpen,BeforeRender, andAfterRender
preview lifecycle events to trusted commands. The preview service passes
report/source metadata plus row, truncation, page, and schema-drift metrics. AddCSharpDbAdminReports(...)now has a command-registration overload for
trusted host applications.- Pipeline packages can now include trusted command hooks for
OnRunStarted,
OnBatchCompleted,OnRunSucceeded, andOnRunFailed. Package JSON stores
hook names, arguments, and generated automation metadata only; command bodies
remain host-registered code. - Pipeline hook failures fail the run through
PipelineRunResult; failure-hook
errors are appended to the failed run summary instead of recursively
dispatching more failure hooks. - Admin Forms command buttons now refresh their executing/disabled state before
and after async command work, so long-running trusted commands give visible
runtime feedback in the form surface.
Stored Automation Metadata
- Added shared
DbAutomationMetadata, command references, and scalar-function
references so portable definitions can declare the trusted host callbacks
they expect without storing C# code. - Admin Forms, Admin Reports, and pipeline packages now regenerate automation
metadata during repository save/load or package serialization/deserialization.
Older JSON without automation metadata is backfilled on read. - Form metadata captures trusted form events, command buttons, selected-control
events, reusable action sequences, action-sequenceRunCommandsteps, and
computed-formula scalar functions. - Report metadata captures preview lifecycle command bindings and calculated
text scalar functions. - Pipeline package metadata captures command hooks and scalar functions used by
filter and derived-column expressions; package validation reports stale
automation manifests so packages can be re-exported.
Developer Experience
- Added
samples/trusted-csharp-host, a VS Code-ready C# host project for
writing and debugging trusted C# callbacks in ordinary application code. - The sample registers a trusted scalar function, calls it from SQL, registers
a trusted command, and runs an Admin Forms action sequence that sets a field
before invoking that command. - The sample includes local
.vscodelaunch/tasks files so developers can open
the sample folder, pressF5, and set breakpoints inside callback code. - The direct Admin launcher now cleans stale Admin artifact snapshots, builds
once, and runs with--no-buildso old generated artifacts do not slow
startup. - Added repo-level MSBuild cleanup for
src/CSharpDB.Admin/artifactsand
default excludes for generated artifact folders. - Added the async I/O batching follow-up note at
docs/query-and-durable-write-performance/async-io-batching-follow-up.md.
Behavior And Safety
- Function names are case-insensitive SQL identifiers, and registration rejects
duplicate user names or collisions with reserved built-ins such asTEXT,
COUNT,SUM,AVG,MIN, andMAX. - Arity is validated before invocation, missing SQL functions fail with the
existing unknown scalar function path, and thrown delegate exceptions are
wrapped with the function name before normal statement/transaction rollback. NullPropagating = truereturnsNULLwithout invoking the delegate when
any argument isNULL; otherwiseDbValue.Nullis passed explicitly.- V1 remains scalar-only, synchronous, trusted, and in-process. It does not
persist C# source, sandbox code, load database-owned plugin assemblies,
marshal delegates over HTTP/gRPC, or add aggregate/table-valued/procedure
UDFs. - Query planning keeps custom functions on the residual expression path in V1:
no index pushdown, generated columns, constant folding, or cost assumptions
are inferred from user functions.
Tests And Benchmarks
- Added registry and SQL coverage for case-insensitive lookup, duplicate and
built-in collision rejection, null propagation, deterministic metadata,
missing functions, thrown functions, rollback behavior, triggers, and stored
SQL procedures. - Added direct-client, Admin Forms, Admin Reports, pipeline validation, and
pipeline runtime tests for registered scalar functions. - Added command-registry, form-event dispatcher, event JSON round-trip, and
Forms data-entry tests for create/update/delete event dispatch and
before-event cancellation. - Added designer-state tests for action sequences, plus command-button and
control-event tests covering event binding preservation and registered
command invocation from rendered forms. - Added Forms action-sequence tests for event dispatch, mutable record updates,
command button action-only clicks, and JSON round-tripping. - Added report-event dispatcher and preview lifecycle tests, pipeline hook
serialization/validation/orchestrator tests, and shared command argument
conversion tests. - Added automation metadata tests covering manifest extraction, JSON
round-tripping, repository persistence/backfill, pipeline package
import/export, and stale package metadata validation. - Added async command and timeout coverage for the command registry, Admin
Forms dispatcher, Admin Reports dispatcher, and pipeline hook orchestration. - Added Forms built-in action tests covering rendered command-button dispatch,
next/previous/go-to navigation, and create/save/refresh/delete workflows. - Added conditional action tests for skip/run behavior, condition failure,
rendered built-in action skipping, metadata propagation, and JSON
round-tripping. - Added parser, planner, SQL execution, direct-client, procedure, query paging,
and Admin completion tests for tablelessSELECT, built-in scalar functions,
BLOB parameter round-tripping, and tableless-safe callback autocomplete. - Added Admin callback catalog tests for tableless callback metadata.
- Added Admin Forms formula evaluator tests for the built-in function catalog
and Access-style formula helpers. - Same-machine affected benchmark comparison against the pre-feature HEAD
baseline showed no material regression in the main write/query guardrails:
| Suite | Worst current change | Best current change |
|---|---|---|
| Insert | +3.76% |
-3.38% |
| Join | +6.65% |
-6.93% |
| PointLookup | +5.15% |
-9.25% |
| QueryPlanCache | +1.62% |
-4.45% |
| ScanProjection | +0.20% |
-18.12% |
| TriggerDispatch | +0.77% |
-4.52% |
| BatchEvaluation | +10.53% |
-10.36% |
The one notable row was the synthetic BatchEvaluation delegate
filter/projection case at +10.53%; its paired specialized path improved by
-10.36%, allocations were unchanged, and the affected guardrail suites were
otherwise neutral to improved.
Validation
git status --short --branchdotnet restore CSharpDB.slnx.\scripts\Test-NoLegacyCoreReferences.ps1- Passed through the script's PowerShell fallback after the local packaged
rg.execould not be launched normally in this desktop environment.
- Passed through the script's PowerShell fallback after the local packaged
dotnet build CSharpDB.slnx -c Release --no-restore- Passed with
0warnings and0errors.
- Passed with
dotnet test CSharpDB.slnx -c Release --no-build -m:1 -- RunConfiguration.DisableParallelization=true- Non-parallel unit test run passed with
1,663tests.
- Non-parallel unit test run passed with
- Phase 5 local validation used
dotnet build CSharpDB.slnx --no-restore -m:1
anddotnet test CSharpDB.slnx --no-build -m:1 -- RunConfiguration.DisableParallelization=true- Debug non-parallel unit test run passed with
1,703tests after adding
automation metadata coverage.
- Debug non-parallel unit test run passed with
- Phase 6A async-command hardening validation used
dotnet build CSharpDB.slnx --no-restore -m:1and
dotnet test CSharpDB.slnx --no-build -m:1 -- RunConfiguration.DisableParallelization=true- Debug non-parallel unit test run passed with
1,709tests.
- Debug non-parallel unit test run passed with
- Phase 6B built-in form action validation used
dotnet build CSharpDB.slnx --no-restore -m:1and
dotnet test CSharpDB.slnx --no-build -m:1 -- RunConfiguration.DisableParallelization=true- Debug non-parallel unit test run passed with
1,712tests.
- Debug non-parallel unit test run passed with
- Phase 6C conditional form action validation used
dotnet build CSharpDB.slnx --no-restore -m:1and
dotnet test CSharpDB.slnx --no-build -m:1 -- RunConfiguration.DisableParallelization=true- Debug non-parallel unit test run passed with
1,715tests.
- Debug non-parallel unit test run passed with
dotnet packsmoke for the release workflow packages with
-p:Version=3.6.0- Produced
11local packages:
CSharpDB,CSharpDB.Client,CSharpDB.Data,CSharpDB.Engine,
CSharpDB.EntityFrameworkCore,CSharpDB.Execution,
CSharpDB.Pipelines,CSharpDB.Primitives,CSharpDB.Sql,
CSharpDB.Storage, andCSharpDB.Storage.Diagnostics.
- Produced
.\scripts\Publish-CSharpDbDaemonRelease.ps1 -Version 3.6.0 -Runtime win-x64 -OutputRoot artifacts\daemon-release-local- Produced
csharpdb-daemon-v3.6.0-win-x64.zipandSHA256SUMS.txt.
- Produced
- Latest tableless/callback stabilization validation used
dotnet test .\CSharpDB.slnx -m:1 --no-restore -v:minimal /nr:false /p:UseSharedCompilation=false /p:TestTfmsInParallel=false -- RunConfiguration.DisableParallelization=true- Debug non-parallel unit test run passed with
1,877tests.
- Debug non-parallel unit test run passed with
Review Notes
- The highest-risk runtime changes are in expression evaluation and planner
plumbing: custom functions are intentionally kept off the index-pushdown and
batch-fast-path planning assumptions in V1. - Remote hosts must register functions in the daemon/API host process; direct
clients can register functions locally throughDirectDatabaseOptions, but
callback delegates are never serialized over HTTP or gRPC. - Admin Forms and Reports use the shared registries, but their formula and
automation surfaces remain narrower than SQL or stored macro systems:
formulas stay expression-focused, command hooks invoke host-owned code by
name, and declarative action sequences store only limited action metadata
rather than executable scripts in database metadata. SELECT ...withoutFROMis represented internally as a single-row source
and is intended for scalar expressions that do not need row context.CanRunWithoutFromis currently discovery metadata for the Admin catalog and
SQL editor autocomplete; it is not yet a hard runtime denial gate for manually
typed tableless callback calls.