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
14 changes: 14 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ Rules:
- Long, descriptive test method names: Start with the SMO object type being tested, then scenario, then expected outcome.
- Always include assertion messages clarifying intent & expected result.
- Logs should make failures diagnosable without rerunning with a debugger.
- For data-driven/parameterized tests, use MSTest attributes (`[DataRow]` or `[DynamicData]`) instead of NUnit attributes (`[TestCase]`, `[TestCaseSource]`, etc.).

Pattern example (pseudo):
```
Expand Down Expand Up @@ -122,6 +123,7 @@ Avoid:
- Placing secret values or tokens in source or tests.
- Publishing internal-only folder content to public mirrors.
- Exposing raw JSON strings in public SMO APIs; wrap them in typed classes.
- Referencing internal work items (e.g., "VSTS #12345", "work item 12345") in code comments, assertions, or documentation. This is externally shipping code; use descriptive text instead.

## 9. Security & Compliance
- Never commit credentials, connection strings with auth info, or access tokens.
Expand Down Expand Up @@ -166,6 +168,18 @@ Many subdirectories include a focused `README.md` describing domain specifics (e

Agent Hint: Before adding or altering code in an unfamiliar area, read the local README to pick up naming, nullability, threading, and performance patterns to mirror.

## 16. Design Specifications

Design specifications for significant features and architectural changes live in the [`/specs`](../specs/) folder. See the [specs README](../specs/README.md) for an index of all specifications.

### Workflow for New Design Work
1. **Before starting any new feature or significant change**, check `/specs` for existing relevant specifications. Read any related specs to understand prior decisions and constraints.
2. **If a spec exists for the work you are doing**, follow its design decisions. If implementation reveals issues with the spec, note discrepancies and propose spec updates.
3. **If no spec exists and the work is significant** (new public API surface, cross-cutting architectural changes, new async patterns, etc.), initiate creation of a new spec before implementation. Use the next available sequence number (`NNNN-short-title.md`) and add it to the index in `/specs/README.md`.
4. **Modification of existing specs** requires updating the status field and preserving the change history in the document.

Agent Hint: When asked to implement a feature, first check `/specs` for a relevant design specification. If one exists, use it as the authoritative source for design decisions. If the work warrants a spec and none exists, propose creating one before proceeding with implementation.

---
Concise Canonical Rules (TL;DR):
1. Always add a failing test for a bug fix.
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
Update this document for externally visible changes. Put most recent changes first.
Once we push a new version to nuget.org add a double hash header for that version.

## 181.15.0

- Fix bug when scripting ALTER USER for Windows Group users

## 181.12.0

- Remove SQL Server 2005 and prior version support:
Expand Down
2 changes: 1 addition & 1 deletion global.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"sdk": {
"version": "8.0.417",
"version": "10.0.103",
"rollForward": "latestMinor"
},
"msbuild-sdks": {
Expand Down
379 changes: 379 additions & 0 deletions specs/0001-async-interfaces.md

Large diffs are not rendered by default.

33 changes: 33 additions & 0 deletions specs/0002-async-scripter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Spec 0002: Async Scripter (ScriptAsync)

**Status:** Placeholder
**Created:** 2026-02-10
**Authors:** SMO Team

## 1. Summary

Add `ScriptAsync()` to the `Scripter` class, enabling fully asynchronous script generation for SMO objects. The `Scripter` walks object trees, reads properties, and emits T-SQL — making it a high-value target for async since scripting large schemas involves many database round-trips.

## 2. Prerequisites

This spec depends on the foundational async infrastructure defined in [0001-async-interfaces.md](0001-async-interfaces.md):

- `SqlSmoObject.InitializeAsync()` / `RefreshAsync()` for async property fetching.
- `SmoCollectionBase.LoadAsync()` for async collection population.
- SFC async layer (`Enumerator.GetDataAsync`).
- `ServerConnection` async execution methods.

## 3. Scope

*To be defined.* This spec will cover:

- `Scripter.ScriptAsync()` method signature and behavior.
- How the scripter asynchronously pre-fetches properties and collections for the objects being scripted.
- Cancellation support via `CancellationToken`.
- Whether scripting can be streamed (`IAsyncEnumerable<string>`) or is batch-only.
- Interaction with `ScriptingOptions` and dependency discovery.
- Testing requirements and parity with synchronous `Script()`.

## 4. Design

*To be completed after [0001-async-interfaces.md](0001-async-interfaces.md) is accepted and implementation is underway.*
115 changes: 115 additions & 0 deletions specs/0003-workload-group-tempdb-rg.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
# Spec 0003: Workload Group TempDB Resource Governance in CREATE Scripts

**Status:** Implemented
**Created:** 2025-11-26
**Implemented:** Commit ce35e55b01c6a51615d708fe3b3d8d8f80790a18
**Authors:** Tong Wu

## 1. Summary

Include TempDB resource governance parameters (`group_max_tempdb_data_mb` and `group_max_tempdb_data_percent`) in `CREATE WORKLOAD GROUP` scripts when their values are explicitly set to `-1` (representing `NULL`). Previously, these parameters were only included in `ALTER` scripts; this change ensures parity between CREATE and ALTER script generation.

## 2. Motivation

TempDB resource governance parameters control the maximum amount of TempDB space a workload group can consume. When creating a workload group via SMO scripting:

- **Before this change:** The `-1` value (representing `NULL`/unlimited) was excluded from CREATE scripts but included in ALTER scripts, leading to inconsistent scripting behavior.
- **After this change:** Both CREATE and ALTER scripts consistently include these parameters when set to `-1`, scripted as `group_max_tempdb_data_mb=null` and `group_max_tempdb_data_percent=null`.

This consistency is important for script generation tools like SSMS Generate Scripts, where users expect CREATE scripts to fully represent the object state.

## 3. Target SQL Server Versions

| Version | Support |
|---------|---------|
| SQL Server 2025 (v17.x) | ✅ Fully supported |
| Azure SQL Managed Instance | ✅ Supported |
| SQL Server 2022 and earlier | ❌ Not applicable |

**Catalog View:** `sys.resource_governor_workload_groups`
**Relevant Columns:** `group_max_tempdb_data_mb`, `group_max_tempdb_data_percent`

## 4. DDL Syntax

### 4.1 CREATE WORKLOAD GROUP

```sql
CREATE WORKLOAD GROUP [group_name] WITH(
group_max_requests=0,
importance=Medium,
request_max_cpu_time_sec=0,
request_max_memory_grant_percent=25,
request_memory_grant_timeout_sec=0,
max_dop=0,
group_max_tempdb_data_mb=null,
group_max_tempdb_data_percent=null) USING [pool_name], EXTERNAL [default]
GO
```

### 4.2 ALTER WORKLOAD GROUP

```sql
ALTER WORKLOAD GROUP [group_name] WITH(
group_max_requests=0,
importance=Medium,
request_max_cpu_time_sec=0,
request_max_memory_grant_percent=25,
request_memory_grant_timeout_sec=0,
max_dop=0,
group_max_tempdb_data_mb=null,
group_max_tempdb_data_percent=null)
GO
```

## 5. SMO Implementation

### 5.1 Properties

| Property | Type | Default | Description |
|----------|------|---------|-------------|
| `GroupMaximumTempdbDataMB` | `double` | `-1` | Maximum TempDB data in MB. `-1` means NULL/unlimited. |
| `GroupMaximumTempdbDataPercent` | `double` | `-1` | Maximum TempDB data as percentage. `-1` means NULL/unlimited. |

### 5.2 Scripting Behavior

| Value | CREATE Script | ALTER Script (when dirty) |
|-------|---------------|---------------------------|
| `-1` | `group_max_tempdb_data_mb=null`, `group_max_tempdb_data_percent=null` | `group_max_tempdb_data_mb=null`, `group_max_tempdb_data_percent=null` |
| `> 0` | `group_max_tempdb_data_mb=<value>`, `group_max_tempdb_data_percent=<value>` | `group_max_tempdb_data_mb=<value>`, `group_max_tempdb_data_percent=<value>` |
| Not set (property not dirty) | Not included | Not included |

### 5.3 Code Location

- **Scripter:** [WorkloadGroupBase.cs](../src/Microsoft/SqlServer/Management/Smo/WorkloadGroupBase.cs)
- **XML Metadata:** [WorkloadGroup.xml](../src/Microsoft/SqlServer/Management/SqlEnum/xml/WorkloadGroup.xml)

## 6. Formatting

The implementation ensures proper formatting with line breaks between tempdb parameters in the WITH clause for readability:

```sql
WITH(group_max_requests=0,
importance=Medium,
request_max_cpu_time_sec=0,
request_max_memory_grant_percent=25,
request_memory_grant_timeout_sec=0,
max_dop=0,
group_max_tempdb_data_mb=null,
group_max_tempdb_data_percent=null)
```

## 7. Testing

Functional tests verify:
1. `-1` values are scripted as `null` in CREATE statements
2. `-1` values are scripted as `null` in ALTER statements (when dirty)
3. Scripts include proper `USING` clause placement after WITH clause

**Test Location:** [WorkloadSmoTests.cs](../src/FunctionalTest/Smo/GeneralFunctionality/WorkloadSmoTests.cs)

## 8. Documentation References

- [Resource Governor Workload Group](https://learn.microsoft.com/sql/relational-databases/resource-governor/resource-governor-workload-group)
- [CREATE WORKLOAD GROUP (Transact-SQL)](https://learn.microsoft.com/sql/t-sql/statements/create-workload-group-transact-sql)
- [ALTER WORKLOAD GROUP (Transact-SQL)](https://learn.microsoft.com/sql/t-sql/statements/alter-workload-group-transact-sql)
- [sys.resource_governor_workload_groups](https://learn.microsoft.com/sql/relational-databases/system-catalog-views/sys-resource-governor-workload-groups-transact-sql)
151 changes: 151 additions & 0 deletions specs/0004-xevent-max-duration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
# Spec 0004: XEvent Session MAX_DURATION Property

**Status:** Implemented
**Created:** 2025-11-15
**Implemented:** Commit f06bad2f6ce804812991b04cdef3e627bfb75228
**Authors:** Kapil Thacker

## 1. Summary

Add support for the `MAX_DURATION` attribute on Extended Events (XEvent) sessions. This property specifies the maximum duration an event session will run before automatically stopping. The feature was introduced in SQL Server 2025.

## 2. Motivation

Extended Events sessions can now have a maximum duration limit, which is useful for:

- **Diagnostic captures:** Automatically stop tracing after a specified time to avoid collecting excessive data.
- **Scheduled monitoring:** Run event sessions for a defined window without manual intervention.
- **Resource management:** Prevent long-running sessions from consuming resources indefinitely.

SMO needs to expose this property to enable SSMS and other tools to script and manage sessions with duration limits.

## 3. Target SQL Server Versions

| Version | Support |
|---------|---------|
| SQL Server 2025 (v17.x) | ✅ Fully supported |
| Azure SQL Database | ⏳ Not yet enabled (tracked by Bug:4806316) |
| Azure SQL Managed Instance | ⏳ Not yet enabled (tracked by Bug:4816977) |
| SQL Server 2022 and earlier | ❌ Not applicable |

**Catalog View:** `sys.server_event_sessions`
**Relevant Column:** `max_duration` (bigint, nullable)

**Note:** The catalog column may not exist on older SQL versions. The SMO implementation uses a conditional `if exists` pattern to check for column existence before executing the dynamic SQL query.

## 4. DDL Syntax

### 4.1 CREATE EVENT SESSION

```sql
CREATE EVENT SESSION [session_name] ON SERVER
ADD EVENT sqlserver.rpc_starting
WITH (MAX_MEMORY=4096 KB,
EVENT_RETENTION_MODE=ALLOW_SINGLE_EVENT_LOSS,
MAX_DISPATCH_LATENCY=30 SECONDS,
MAX_EVENT_SIZE=0 KB,
MEMORY_PARTITION_MODE=NONE,
TRACK_CAUSALITY=OFF,
STARTUP_STATE=OFF,
MAX_DURATION=UNLIMITED)
GO
```

### 4.2 MAX_DURATION Values

| Value | T-SQL Syntax | Description |
|-------|--------------|-------------|
| `0` | `MAX_DURATION=UNLIMITED` | Session runs indefinitely (engine default when omitted) |
| `> 0` | `MAX_DURATION=<n> SECONDS` | Session stops after `n` seconds |

### 4.3 Example with Specific Duration

```sql
CREATE EVENT SESSION [session_name] ON SERVER
ADD EVENT sqlserver.rpc_starting
WITH (MAX_DURATION=3600 SECONDS) -- 1 hour
GO
```

## 5. SMO Implementation

### 5.1 Properties

| Property | Type | SMO Default | Description |
|----------|------|-------------|-------------|
| `MaxDuration` | `long` | `DefaultMaxDuration` (-1) | Duration in seconds. `0` means unlimited. `-1` is the SMO sentinel for "not explicitly set". |

### 5.2 Constants

```csharp
public const long DefaultMaxDuration = -1; // Property not explicitly set
public const long UnlimitedDuration = 0; // Explicitly set to UNLIMITED
```

### 5.3 Scripting Behavior

| Value | Script Output |
|-------|---------------|
| `-1` (default) | Property omitted from script |
| `0` (unlimited) | `MAX_DURATION=UNLIMITED` |
| `> 0` | `MAX_DURATION=<value> SECONDS` |

The property is only included in scripts when explicitly set (not default `-1`), ensuring backward compatibility with existing scripts.

### 5.4 Code Locations

- **Session Class:** [Session.cs](../src/Microsoft/SqlServer/Management/XEvent/core/Session.cs)
- **Session Provider:** [SessionProviderBase.cs](../src/Microsoft/SqlServer/Management/XEvent/core/SessionProviderBase.cs)
- **XML Metadata:** [Session.xml](../src/Microsoft/SqlServer/Management/XEventEnum/xml/Session.xml)

### 5.5 XML Metadata Implementation

The implementation uses a conditional query pattern to handle version differences:

```xml
<property_link fields='#MaxDuration#' left_join='#md' alias='maxdur'>
maxdur.event_session_id = session.event_session_id
</property_link>
<prefix fields='#MaxDuration#'>
create table #md (event_session_id int not null, max_duration bigint null)
if exists (select 1 from sys.all_columns
where object_id = object_id('sys.server_event_sessions')
and name = 'max_duration')
begin
declare @sql nvarchar(max) = 'insert into #md select event_session_id, max_duration from sys.server_event_sessions'
exec sp_executesql @sql
end
</prefix>
```

This pattern ensures queries don't fail on older SQL versions lacking the column.

## 6. Testing

### 6.1 Unit Tests

- Verify default value is `DefaultMaxDuration`
- Verify property initialization on new sessions

**Test Location:** [SessionUnitTest.cs](../src/FunctionalTest/Smo/XEvent/SessionUnitTest.cs)

### 6.2 Functional Tests

- `MaxDuration_CreateSession_WithUnlimitedValue_IncludesInScript`: Verify `MAX_DURATION=UNLIMITED` appears when set to `0`
- `MaxDuration_CreateSession_WithValidValue_IncludesInScript`: Verify `MAX_DURATION=<n> SECONDS` appears for positive values
- Tests verify default value omits `MAX_DURATION` from script

**Test Location:** [XEventSessionTests.cs](../src/FunctionalTest/Smo/XEvent/XEventSessionTests.cs)

### 6.3 Version Restrictions

Tests are restricted to:
- SQL Server 2025+ (`MinMajor = 17`)
- Standalone engine type only (not Managed Instance until Bug:4816977 is resolved)

## 7. Documentation References

- [CREATE EVENT SESSION (Transact-SQL)](https://learn.microsoft.com/sql/t-sql/statements/create-event-session-transact-sql)
- [ALTER EVENT SESSION (Transact-SQL)](https://learn.microsoft.com/sql/t-sql/statements/alter-event-session-transact-sql)
- [sys.server_event_sessions](https://learn.microsoft.com/sql/relational-databases/system-catalog-views/sys-server-event-sessions-transact-sql)
- [Extended Events Overview](https://learn.microsoft.com/sql/relational-databases/extended-events/extended-events)
Loading