Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/JSuder-xx/TSqlStrong
T-Sql type checker that detects improper joins, invalid null value operations, enumeration check constraint violations, incorrect use of temporary table at call site, more. On-line demo available.
https://github.com/JSuder-xx/TSqlStrong
check-constraints enumeration flow-typing flowtype null-safety sql static-code-analysis t-sql
Last synced: 26 days ago
JSON representation
T-Sql type checker that detects improper joins, invalid null value operations, enumeration check constraint violations, incorrect use of temporary table at call site, more. On-line demo available.
- Host: GitHub
- URL: https://github.com/JSuder-xx/TSqlStrong
- Owner: JSuder-xx
- License: mit
- Created: 2018-04-24T00:01:52.000Z (about 6 years ago)
- Default Branch: master
- Last Pushed: 2018-05-14T23:53:11.000Z (about 6 years ago)
- Last Synced: 2024-02-29T08:32:06.194Z (4 months ago)
- Topics: check-constraints, enumeration, flow-typing, flowtype, null-safety, sql, static-code-analysis, t-sql
- Language: C#
- Homepage: http://tsqlstrongdemo.azurewebsites.net/
- Size: 363 KB
- Stars: 11
- Watchers: 6
- Forks: 6
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Lists
- sqlserver-kit - TSqlStrong - T-Sql type checker that detects improper joins, possibly null value operations, enumeration check constraint violations, incorrect use of temporary table at call site, and more
README
# Overview
T-SQL Strong is a T-SQL type checker/verifier that will
* Verify the correctness of T-Sql code before it executes against a database.
* Advanced type checking features include
* Key Column Comparison - Protects against incorrect joins.
* Null Type Checking - Guard against run-time errors of assigning a null value to a non-null column.
* Check Constraints As Enumerations - Ensure only valid literals are assigned or compared against check constraint columns.
* Insert Into Select Alias Matching - Protect against positional mistakes made with insert-select where you have many columns.
* Verify the correctness of Temporary Table structure usage between different stored procedures.
* Flow Typing. TSqlStrong can learn more about types (refinement) by analyzing flow control (IF/ELSEIF, CASE).[Try it out online](http://tsqlstrongdemo.azurewebsites.net)
# Examples
### Key Column Comparison
```sql
create table Parent (
id int not null,
constraint PK_Parent primary key clustered (id)
);create table Child (
id int not null,
Parent_id int not null foreign key references Parent(id),
constraint PK_Child primary key clustered (id)
);-- OK
select * from Parent inner join Child on Child.Parent_ID = Parent.ID
-- Error
select * from Parent inner join Child on Child.ID = Parent.ID
```### Null Type Checking
```sql
declare @tableWithNulls table (val int null);
declare @tableWithoutNulls table (val int not null);-- OK
insert into @tableWithNulls
select val from @tableWithoutNulls;-- TypeError
insert into @tableWithoutNulls
select val from @tableWithNulls;-- OK
insert into @tableWithoutNulls
select COALESCE(val, 0) from @tableWithNulls;-- when declaring a variable and immediately setting it to a non-null
-- TSqlStrong knows the value is not null.
declare @someInt int = 10;-- OK. The value was initialized to not null.
insert into @tableWithoutNulls values (@someInt);declare @someOtherInt int;
-- ERROR. TSqlStrong saw that @someInt became null.
insert into @tableWithoutNulls values (@someOtherInt);if (@someOtherInt is not null)
begin
-- OK. TSqlStrong knows that @someOtherInt is not null at this point thanks to the check.
insert into @tableWithoutNulls values (@someInt);
end;
```### Check Constraints Understood as Enumerations
#### Literal Values
```sql
create table Person
(
gender varchar(40)
constraint ck_Person_Gender
check (
(gender = 'male')
or (gender = 'female')
or (gender = 'other')
or (gender = 'unknown')
)
)-- OK
insert into Person (gender)
values
('female'),
('other'),
('male');-- Type Error
insert into Person (gender)
values ('hello');
```#### Case Determination
TSqlStrong can figure out all possible values returned by a CASE expression and can check that against your check constraint columns.
```sql
create table Person
(
gender varchar(40)
constraint ck_Person_Gender
check (
(gender = 'male')
or (gender = 'female')
or (gender = 'other')
or (gender = 'unknown')
)
)
GOdeclare @someInt int;
-- OK
insert into Person (gender)
values
(case
when @someInt is null then 'unknown'
when @someInt > 0 then 'female'
else 'male'
end);-- Type Error due to 'apple'
insert into Person (gender)
values
(case
when @someInt is null then 'unknown'
when @someInt > 0 then 'apple'
else 'male'
end);
```### Insert Into Select - Alias Matching
```sql
-- Type Error:
insert into TableOfManyColumns (A, B, C, D /*,...Z*/)
select
1 as A,
'Hi' as B,
13 as C,
'Bye' as E, -- Error: Expected D in this position
/* ...Z */
from
SomeOtherWideTable
```### Temporary Table Structure Checking
```sql
create procedure dbo.SelectFirstAndLastNameFromTemp
as
begin
select firstName, lastName from #Temp;
end;
GOcreate procedure dbo.CallsSelectFirstAndLastNameFromTemp
as
begin
exec dbo.SelectFirstAndLastNameFromTemp;
end;
GOcreate procedure dbo.CreateWithFullNameAndExecuteIndirect
as
begin
create table #Temp (fullName varchar(200));-- ERROR: When called from here the temp table does not have the correct structure.
exec dbo.CallsSelectFirstAndLastNameFromTemp;
end;
GOcreate procedure dbo.CreateWithFirstAndLastNameAndExecuteIndirect
as
begin
create table #Temp (firstName varchar(200), lastName varchar(200));
-- OK: When called from here it is just fine.
exec dbo.CallsSelectFirstAndLastNameFromTemp;
end;
GO
```### Common Table Expressions
```sql
with Recurse (Num)
as
(
select 0union all
-- ERROR: Num is an Int from the base case
select Num + 'apples'
from Recurse
)
select top 10 Num from Recurse;with Recurse (Num)
as
(
select 0union all
-- ERROR: NumX is not in the list of Recurse
select NumX
from Recurse
)
select top 10 Num from Recurse;-- ERROR: Column count mismatch between CTE and union.
with Recurse (Num)
as
(
select 0, 1union all
select Num, 20
from Recurse
)
select top 10 Num from Recurse;-- GOOD!
with Recurse (Num)
as
(
select 0union all
select Num + 1
from Recurse
)
select top 10 Num from Recurse;with NonRecursive (Num)
as
(
select 0
union all
select 1
union all
select 2
)
select *
from
NonRecursive
where
-- ERROR: TSqlStrong figured out Num can only be 0, 1, or 2 so this comparison check makes no sense.
Num = 4;-- GOOD
with NonRecursive (Num)
as
(
select 0
union all
select 1
union all
select 2
)
select *
from
NonRecursive
where
Num = 2;
```### Flow Typing
#### Null Checking
```sql
create table Person (weight int not null)
GOdeclare @someInt int; -- NOTE: All variables are nullable by default.
insert into Person select @someInt; -- ERROR: Possible nullable assignment to non-null.
insert into Person select Coalesce(@someInt, 1); -- OK.
insert into Person select IsNull(@someInt, 1); -- OK.if (@someInt is not null)
begin
insert into Person select @someInt; -- OK
end
else
begin
insert into Person select @someInt; -- TYPE ERROR
end;
```#### Enumerations
```sql
create table Person
(
gender varchar(40)
not null
constraint ck_Person_Gender
check (
(gender = 'male')
or (gender = 'female')
or (gender = 'other')
or (gender = 'unknown')
)
)
GOdeclare @randomText varchar(100);
insert into Person select coalesce(@randomText, 'unknown'); -- TYPE ERROR
if (@randomText = 'male') or (@randomText = 'female') or (@randomText = 'other')
begin
-- OK. TSqlStrong knows randomText must be 'male', 'female', 'other'.
insert into Person select @randomText;
end;
```# Usage
The project is currently a proof of concept. See ROADMAP for where it is heading.* Fork or download the source from GitHub and build. TSqlStrong was developed in Visual Studio 2017 Community Edition.
* Sql text can be verified using the command line interface TSqlStrongCli.
* Example Sql can be found in \TSqlStrongDemoWebApp\wwwroot\sql
* A build task for Visual Studio Code can be found in \TSqlStrongCli\VSCodeIntegration.