Skip to content

Commit 43be596

Browse files
committed
Enhance support for CLR stored procedures and table-valued functions
- Updated SqlChangeTracker to include CLR stored procedures (type 'PC') and table-valued functions (type 'FT') in the introspection and scripting processes. - Added functionality to script CLR stored procedures and table-valued functions, including their parameters and return types. - Enhanced the normalization process for CLR table-valued functions to suppress differences related to NULL tokens and formatting. - Implemented tests to verify the inclusion and correct scripting of CLR objects. - Updated the SyncCommandService to handle differences in CLR functions and queues more effectively.
1 parent f59f9c9 commit 43be596

12 files changed

Lines changed: 1035 additions & 19 deletions

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
1010
### Fixed
1111
- Script schema-level permissions after schema creation and before schema extended properties.
1212
- Match legacy non-canonical schema-less object filenames to the scripted object name when the canonical name requires percent escaping.
13+
- Treat equivalent queue option formatting, explicit default `ON [PRIMARY]`, and disabled default activation as compatible during comparison.
14+
- Treat legacy explicit `NULL` tokens on CLR table-valued function return columns as compatible during comparison and preserve them during compatibility reconciliation when the rest of the definition matches.
1315
- Trailing semicolon differences on `INSERT` statement lines in data scripts are now suppressed during comparison normalization; scripts emitted with and without statement terminators compare as compatible (#47).
1416
- Legacy `TableData` scripts now compare as compatible when they differ from canonical output only by `SET IDENTITY_INSERT` semicolons or top-level `N'...'` string literal prefixes, including inside multi-line `INSERT ... VALUES (...)` statements.
1517
- Whitespace-only separator lines now compare as compatible with empty blank lines during `status` and `diff`.
1618
- Preserve reference banner-comment formatting and module-declaration identifier quoting during programmable-object compatibility reconciliation.
1719
- Preserve compatible computed-column arithmetic grouping parentheses during table compatibility reconciliation.
1820

1921
### Added
22+
- Discover and script SQL CLR scalar functions as `Function` objects.
23+
- Discover and script SQL CLR table-valued functions as `Function` objects.
24+
- Discover and script SQL CLR stored procedures as `StoredProcedure` objects.
2025
- `sqlct init` now prompts interactively for connection details (server, database, auth, credentials, trust-server-certificate) when run without flags in a new project directory (#36).
2126
- Connection flags (`--server`, `--database`, `--auth`, `--user`, `--password`, `--trust-server-certificate`) for non-interactive/scripted `init` use (#36).
2227
- `--skip-connection-test` flag for `sqlct init` to bypass the connection test step (#36).

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,12 @@ Current runtime scope for `status`, `diff`, and `pull` covers:
5252
- `FullTextStoplist`
5353
- `SearchPropertyList`
5454

55+
Stored procedure scripting covers T-SQL procedures and SQL CLR stored procedures (`sys.objects.type = 'P'` and `PC`).
56+
5557
Table scripting also includes standalone user-created table statistics (`CREATE STATISTICS`) as post-create table statements. Current statistics option coverage includes effective sampling (`FULLSCAN` or `SAMPLE <n> PERCENT`), `PERSIST_SAMPLE_PERCENT = ON`, `NORECOMPUTE`, `INCREMENTAL=ON`, and `AUTO_DROP = ON|OFF` when the source server exposes the required metadata. `MAXDOP`, `STATS_STREAM`, `ROWCOUNT`, and `PAGECOUNT` remain deferred.
5658

59+
Function scripting covers T-SQL scalar/table functions and SQL CLR scalar/table-valued functions (`sys.objects.type = 'FS'` and `FT`), including `EXTERNAL NAME` assembly bindings.
60+
5761
When `data.trackedTables` is configured, `status`, `diff`, and `pull` also process `TableData` artifacts for those explicit tracked tables.
5862

5963
`--object` selectors support:

specs/01-cli.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -195,9 +195,10 @@ Behavior:
195195
- Deleted: object exists only in target.
196196
- Changed: normalized script content differs.
197197
- Suppress changes when scripts are identical after normalization.
198-
- Normalization in v1 is limited to line-ending/trailing-newline stability for deterministic comparison.
198+
- Normalization includes line-ending/trailing-newline stability plus explicitly listed compatibility rules for deterministic comparison.
199199
- Whitespace-only lines are normalized to empty lines during comparison so blank separators with spaces or tabs compare as compatible.
200200
- Trailing semicolons on `INSERT` statement lines are stripped during normalization; scripts emitted with and without statement terminators compare as compatible.
201+
- Equivalent `Queue` option spacing, line wrapping, explicit default `ON [PRIMARY]`, and disabled default activation compare as compatible.
201202
- When `data.trackedTables` is configured, `status` also reports data-script differences for tracked tables.
202203
- Status output MUST report schema and data summaries separately.
203204
- Exit codes:
@@ -217,9 +218,10 @@ Behavior:
217218
- Without `--object`, output concatenated per-object diffs in stable order.
218219
- Changed objects use DB-vs-folder unified diff.
219220
- Added/deleted objects use empty-side vs script-side unified diff.
220-
- Normalization in v1 is limited to line-ending/trailing-newline stability for deterministic comparison.
221+
- Normalization includes line-ending/trailing-newline stability plus explicitly listed compatibility rules for deterministic comparison.
221222
- Whitespace-only lines are normalized to empty lines during comparison so blank separators with spaces or tabs compare as compatible.
222223
- Trailing semicolons on `INSERT` statement lines are stripped during normalization; scripts emitted with and without statement terminators compare as compatible.
224+
- Equivalent `Queue` option spacing, line wrapping, explicit default `ON [PRIMARY]`, and disabled default activation compare as compatible.
223225
- Diff output uses a chunked format: only changed lines and their surrounding context are shown, not the entire file.
224226
- `--context <N>` controls the number of unchanged context lines shown before and after each changed segment (default: 3). Negative values are treated as 0.
225227
- When two change segments are close enough that their context regions overlap, they are merged into a single hunk.

specs/04-scripting.md

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ This specification defines normative scripting rules for `sqlct`.
6666
- Assemblies
6767
- Views
6868
- Stored Procedures
69-
- Functions (`FN`, `TF`, `IF`)
69+
- Functions (`FN`, `TF`, `IF`, `FS`, `FT`)
7070
- Sequences
7171
- Schema
7272
- Role
@@ -373,8 +373,13 @@ Each emitted statement MUST be followed by `GO`.
373373
2. index-level (by index name, then property name).
374374

375375
### 8.3 Stored Procedures
376-
- Stored procedures are scripted through programmable-object framing rules with object type `P` and level type `PROCEDURE`.
377-
- Definition text MUST come from `OBJECT_DEFINITION`.
376+
- Stored procedures are scripted through programmable-object framing rules with object types `P`, `PC` and level type `PROCEDURE`.
377+
- T-SQL stored procedure definition text for `P` MUST come from `OBJECT_DEFINITION`.
378+
- CLR stored procedure (`PC`) metadata MUST be sourced from `sys.assembly_modules`, `sys.assemblies`, and `sys.parameters`.
379+
- CLR stored procedure (`PC`) output MUST emit:
380+
- `CREATE PROCEDURE [schema].[name] (<parameters>)`
381+
- optional `WITH EXECUTE AS <CALLER|OWNER|'principal'>`
382+
- `AS EXTERNAL NAME [assembly].[class].[method]`
378383
- Regex replacements from overrides MUST be applied before compatibility line-map reconciliation.
379384
- Compatibility definition line-map reconciliation MUST be applied when reference file exists.
380385
- When no compatible reference spacing is preserved, procedure emission MUST use the canonical programmable-object whitespace rules from Section 6.1.
@@ -388,8 +393,24 @@ Each emitted statement MUST be followed by `GO`.
388393
2. parameter-level (by parameter name, then property name).
389394

390395
### 8.4 Functions
391-
- Functions are scripted through programmable-object framing rules with object types `FN`, `TF`, `IF` and level type `FUNCTION`.
392-
- Definition text MUST come from `OBJECT_DEFINITION`.
396+
- Functions are scripted through programmable-object framing rules with object types `FN`, `TF`, `IF`, `FS`, `FT` and level type `FUNCTION`.
397+
- T-SQL function definition text for `FN`, `TF`, and `IF` MUST come from `OBJECT_DEFINITION`.
398+
- CLR function metadata for `FS` and `FT` MUST be sourced from `sys.assembly_modules`, `sys.assemblies`, and `sys.parameters`.
399+
- CLR scalar function (`FS`) output MUST emit:
400+
- `CREATE FUNCTION [schema].[name] (<parameters>)`
401+
- `RETURNS <return_type>`
402+
- `WITH EXECUTE AS <CALLER|OWNER|'principal'>`
403+
- `EXTERNAL NAME [assembly].[class].[method]`
404+
- CLR table-valued function (`FT`) return-column metadata MUST be sourced from `sys.columns`, `sys.types`, and type-schema metadata for the function object.
405+
- CLR table-valued function (`FT`) order metadata MUST be sourced from `sys.function_order_columns` when available.
406+
- CLR table-valued function (`FT`) output MUST emit:
407+
- `CREATE FUNCTION [schema].[name] (<parameters>)`
408+
- `RETURNS TABLE (`
409+
- one return column per line in `column_id` order using `[name] <type>`
410+
- `)`
411+
- `WITH EXECUTE AS <CALLER|OWNER|'principal'>`
412+
- optional `ORDER ([column_1] <ASC|DESC>, [column_2] <ASC|DESC>, ...)` ordered by `order_column_id`
413+
- `EXTERNAL NAME [assembly].[class].[method]`
393414
- Regex replacements from overrides MUST be applied before final emission.
394415
- When no compatible reference spacing is preserved, function emission MUST use the canonical programmable-object whitespace rules from Section 6.1.
395416
- Grants and extended properties MUST follow module body.
@@ -781,6 +802,8 @@ When compatibility reference files are available, `sqlct` MAY apply reconciliati
781802
- Trailing semicolons on `INSERT` statement lines MUST be stripped by comparison normalization so that scripts emitted with and without statement terminators compare as compatible.
782803
- For `TableData`, trailing semicolons on `SET IDENTITY_INSERT` lines MUST also be stripped by comparison normalization.
783804
- For `TableData`, comparison normalization MUST treat legacy top-level `N'...'` string literals inside single-line or multi-line `INSERT ... VALUES (...)` statements as compatible with canonical `'...'` literals; canonical script generation remains governed by Section 8.26.
805+
- For `Queue`, comparison normalization MUST treat equivalent single-line and multi-line queue option formatting as compatible, MAY treat explicit `ON [PRIMARY]` as equivalent to an omitted default primary filegroup, and MAY treat disabled activation containing only default owner execution context as equivalent to omitted activation.
806+
- For CLR table-valued `Function` scripts, comparison normalization MAY treat legacy explicit `NULL` tokens on return-column lines as compatible with canonical return-column lines that omit nullability, including legacy cases where the final return-column line also carries the closing `)` token.
784807

785808
## 11. Error and Unsupported Behavior
786809
- Missing SQL object metadata for requested object MUST fail with an error.

src/SqlChangeTracker/PACKAGE_README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,12 @@ Current runtime scope for `status`, `diff`, and `pull` covers:
5353
- `FullTextStoplist`
5454
- `SearchPropertyList`
5555

56+
Stored procedure scripting covers T-SQL procedures and SQL CLR stored procedures (`sys.objects.type = 'P'` and `PC`).
57+
5658
Table scripting also includes standalone user-created table statistics (`CREATE STATISTICS`) as post-create table statements. Current statistics option coverage includes effective sampling (`FULLSCAN` or `SAMPLE <n> PERCENT`), `PERSIST_SAMPLE_PERCENT = ON`, `NORECOMPUTE`, `INCREMENTAL=ON`, and `AUTO_DROP = ON|OFF` when the source server exposes the required metadata. `MAXDOP`, `STATS_STREAM`, `ROWCOUNT`, and `PAGECOUNT` remain deferred.
5759

60+
Function scripting covers T-SQL scalar/table functions and SQL CLR scalar/table-valued functions (`sys.objects.type = 'FS'` and `FT`), including `EXTERNAL NAME` assembly bindings.
61+
5862
When `data.trackedTables` is configured, `status`, `diff`, and `pull` also process `TableData` artifacts for those explicit tracked tables.
5963

6064
Feature-backed object types are included when the target database exposes them, such as `FullTextCatalog`, `FullTextStoplist`, and `SearchPropertyList`.

src/SqlChangeTracker/Sql/SqlServerIntrospector.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ FROM sys.assemblies a
2323
SELECT s.name AS schema_name, o.name AS object_name, o.type
2424
FROM sys.objects o
2525
JOIN sys.schemas s ON s.schema_id = o.schema_id
26-
WHERE o.is_ms_shipped = 0 AND o.type IN ('U','V','P','FN','TF','IF')
26+
WHERE o.is_ms_shipped = 0 AND o.type IN ('U','V','P','PC','FN','TF','IF','FS','FT')
2727
ORDER BY s.name, o.name;", MapObjectType),
2828

2929
() => RunQuery(options, @"
@@ -401,7 +401,7 @@ FROM sys.objects o
401401
FROM sys.objects o
402402
JOIN sys.schemas s ON s.schema_id = o.schema_id
403403
WHERE o.is_ms_shipped = 0
404-
AND o.type = 'P'
404+
AND o.type IN ('P','PC')
405405
AND s.name = @schema
406406
AND o.name = @name
407407
ORDER BY s.name, o.name;
@@ -416,7 +416,7 @@ FROM sys.objects o
416416
FROM sys.objects o
417417
JOIN sys.schemas s ON s.schema_id = o.schema_id
418418
WHERE o.is_ms_shipped = 0
419-
AND o.type IN ('FN','TF','IF')
419+
AND o.type IN ('FN','TF','IF','FS','FT')
420420
AND s.name = @schema
421421
AND o.name = @name
422422
ORDER BY s.name, o.name;
@@ -715,8 +715,8 @@ private static string MapObjectType(string type)
715715
"ASSEMBLY" => "Assembly",
716716
"U" => "Table",
717717
"V" => "View",
718-
"P" => "StoredProcedure",
719-
"FN" or "TF" or "IF" => "Function",
718+
"P" or "PC" => "StoredProcedure",
719+
"FN" or "TF" or "IF" or "FS" or "FT" => "Function",
720720
"SQ" => "Sequence",
721721
"SC" => "Schema",
722722
"SY" => "Synonym",

0 commit comments

Comments
 (0)