Add support for XEvent logging and bump API version to v3#90
Add support for XEvent logging and bump API version to v3#90miljann995 wants to merge 22 commits into
Conversation
There was a problem hiding this comment.
Pull request overview
This PR introduces a v3 extension interface update to support optional host callbacks, enabling extensions (specifically the .NET C# extension) to log XEvents back through the host infrastructure.
Changes:
- Bumped
EXTERNAL_LANGUAGE_EXTENSION_APIfrom 2 to 3 and added a new optionalSetHostCallbacksAPI + callback struct/type in the shared native interface header. - Implemented native
SetHostCallbacksin the .NET C# extension and forwarded the callback struct to the managed layer. - Added managed callback delegates/structs plus a
Logging.LogXEvent(...)helper that invokes the host-provided callback.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| extension-host/include/sqlexternallanguage.h | Bumps API version to v3; adds host callback typedef/struct and SetHostCallbacks API declaration. |
| language-extensions/dotnet-core-CSharp/include/nativecsharpextension.h | Declares SetHostCallbacks export and stores a host-callbacks pointer. |
| language-extensions/dotnet-core-CSharp/src/native/nativecsharpextension.cpp | Implements native SetHostCallbacks; resets host callbacks on cleanup. |
| language-extensions/dotnet-core-CSharp/src/managed/CSharpExtension.cs | Adds managed callback delegate/struct and implements managed SetHostCallbacks. |
| language-extensions/dotnet-core-CSharp/src/managed/utils/Logging.cs | Stores callback delegate and adds LogXEvent helper for managed code. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
SicongLiu2000
left a comment
There was a problem hiding this comment.
Review Summary — XEvent Logging Callback API (v3)
Nice feature — clean API surface and good test coverage. Three items I'd want addressed before merge, plus several medium-severity hardening suggestions:
Must-fix (High)
- TOCTOU on
_logXEventCallback(Logging.cs) — snapshot to local before null-check and invocation to prevent NRE from concurrentSetLogXEventCallback(null). - Use-after-free in
Cleanup()(nativecsharpextension.cpp) — must clear the managed-side callback delegate before tearing down the .NET runtime, otherwise background threads can invoke a stale host function pointer. char*vsbyte*delegate type mismatch (CSharpExtension.cs) — delegate declareschar*(2-byte UTF-16) but actually receivesbyte*(1-byte UTF-8). Should bebyte*to match the nativeSQLCHAR*.
Should-fix (Medium)
- Dangling pointer —
g_hostCallbacksstores borrowed pointer; copy the struct or remove the dead global. fixedon empty array — yields null pointer passed to native code; guard the empty-message case.staticglobals in header — pre-existing issue, but the newg_hostCallbacksfollows the pattern;extern+ single definition is correct.
Consider (Low)
- Version check could use a
MAX_SUPPORTEDconstant for future extensibility. ulongvsnuintforSQLULENif 32-bit is ever a target.
See inline comments for details and suggested fixes.
SicongLiu2000
left a comment
There was a problem hiding this comment.
All 8 findings addressed — TOCTOU snapshot, use-after-free ordering, type mismatch, dangling pointer copy, fixed-null guard, extern globals, version constant, and typo. Good test coverage with the new GTest suite. LGTM 👍
| // | ||
| #define SQLEXTENSION_HOST_CALLBACKS_VERSION_1 1 | ||
|
|
||
| typedef struct _SQLEXTENSION_HOST_CALLBACKS |
There was a problem hiding this comment.
the struct mismatches with the latest one in the engine
There was a problem hiding this comment.
typedef struct _SQLEXTENSION_HOST_CALLBACKS
{
SQLUSMALLINT Version; // 2 bytes
SQLUSMALLINT Reserved0; // 2 bytes (explicit padding)
SQLUINTEGER SizeInBytes; // 4 bytes
PFunc_ExtensionLogXEvent LogXEvent; // 8 bytes (pointer)
void *Reserved1; // 8 bytes
void *Reserved2; // 8 bytes
} SQLEXTENSION_HOST_CALLBACKS; // Total: 32 bytes
| SQLEXTENSION_INTERFACE | ||
| SQLRETURN Cleanup(); | ||
|
|
||
| // Trace levels for events logged from via LogXEvent function. |
There was a problem hiding this comment.
We need to use the latest commit in our internal repo (this is used as git submodule there), generate nugets there, consume it in your DsMainDev private branch, run PVS with it.
| // Lowest numeric value is the most severe, matching the Windows ETW | ||
| // TRACE_LEVEL_* convention. | ||
| // | ||
| enum ExtensionTraceLevel |
There was a problem hiding this comment.
sqlexternallanguage.h to stay similar with what we have in the engine;
right now this enum is not in the same place in the engine code.
can we move ExtensionTraceLevel in there also to sqlexternallanguage.h?
|
|
||
| // Host callbacks pointer provided by the host via SetHostCallbacks. | ||
| // | ||
| static SQLEXTENSION_HOST_CALLBACKS* g_hostCallbacks = nullptr; No newline at end of file |
There was a problem hiding this comment.
g_hostCallbacks is a raw pointer to host-owned memory (CExthostExtensionManager::m_hostCallbacks in DsMainDev). Its lifetime is valid from SetHostCallbacks until Cleanup. Please add a comment documenting this ownership contract so future contributors don't cache or use it after Cleanup.
c3c4392 to
875619b
Compare
This reverts commit 7b6bdb3.
…nsion name otherwise
875619b to
2f9a8c9
Compare
This pull request introduces a new optional host callback API (version 3) for SQL language extensions, enabling extensions to log XEvents back to the host infrastructure. The update defines new callback types and structures in the native interface, implements the callback registration and invocation in both native and managed (.NET) layers, and provides the necessary glue to allow the managed extension to log messages through the host's event system.
The most important changes are:
API and Interface Additions:
EXTERNAL_LANGUAGE_EXTENSION_APIversion from 2 to 3 insqlexternallanguage.hto indicate the new optional host callback API.PFunc_ExtensionLogXEventcallback type, theSQLEXTENSION_HOST_CALLBACKSstructure, and theSetHostCallbacksAPI tosqlexternallanguage.h, allowing the host to provide callback functions to extensions.Native Extension Integration:
SetHostCallbacksfunction and theg_hostCallbackspointer tonativecsharpextension.hand implemented their logic innativecsharpextension.cpp, storing the host callbacks and forwarding them to the managed layer. [1] [2]Managed Extension Support:
CSharpExtension.cs, and implemented theSetHostCallbacksmethod to receive and store the callback, enabling managed code to log XEvents through the host.Loggingutility inLogging.csto store the host-provided callback and added theLogXEventmethod, allowing managed code to log messages through the host's XEvent infrastructure. [1] [2]Here's the compatibility matrix for general Extension API in terms of host callbacks.
SetHostCallbacksis not defined in Extension and host does not expect it and does not call it.SetHostCallbacksis not defined in Extension, but host does check it and skips calling it since it's not defined on Extension side.SetHostCallbacksis defined in Extension but host does not expect it and does not call it.SetHostCallbacksis defined on both sides and host calls it.Here's the compatibility matrix for Host Callbacks API. Here,
v2can be interpreted asvNext.v1is the current version present in this pull request.LogXEventcallback and Extension expects only that one, and saves its address.LogXEvent, but Extension reads onlyLogXEvent, ignoring other callbacks.LogXEventcallback, and Extension expects additional functions apart fromLogXEvent, but since they arenullptrin a struct, they will be skipped.LogXEvent, and Extension expects additional functions apart fromLogXEvent, saves their addresses and calls them.