tSQLt How can I tell if a table has been faked - sql

I am just starting creating some unit tests for my database.
If I have faked a table,
EXEC tSQLt.FakeTable
#TableName = 'dbo.[My Table]',
#Identity = 0,
#ComputedColumns = 0,
#Defaults = 0
Can I check if it has been faked?
Note that documentation on the FakeTable SP can be found here.
Motivation
I want to be able to do this as I imagine creating several stored procedures which populate these faked tables so I can perform tests.
However I do not want to handle faking the tables in the stored procedures (so I can call them multiple times entering different info each time).
I don't want to have the possibility that I forget to fake the table before adding the data (as would almost certainly cause me to fail my test).

tSQLt adds an extended property to a fake table to track the table it fakes. This is easily tested using the function tSQLt.Private_GetOriginalTableName:
SELECT tSQLt.Private_GetOriginalTableName('dbo','[My Table]')
This will return NULL if the table isn't faked.
If you want to do something more complex, you can query sys.extended_properties directly. See the contents of the tSQLt.class.sql script (in the tSQLt distribution) for the definition of tSQLt.Private_GetOriginalTableName.

You can check for the existence of the table at the beginning of your stored procedure(s).
If Not Exists ( Select 1 From Sys.Objects Where [Name] = 'YOURTABLENAME' And [Type] = 'U')
Begin
-- Your Create Table Statement Here
ENd
Based on your comments, the tool has to be doing something like this, using schema:
Create table dbo.MisterPositive ( test int )
Create table developers.MisterPositive (test Int )
-- Both statements below work
Select * From dbo.MisterPositive
Select * From developers.MisterPositive
-- Use this to look for existence prior
Select 1 from sys.objects
Inner join sys.schemas ON sys.objects.schema_id = sys.schemas.schema_id
where sys.objects.[Name] = 'MisterPositive' And sys.schemas.name = 'dbo'
Select 1 from sys.objects
Inner join sys.schemas ON sys.objects.schema_id = sys.schemas.schema_id
where sys.objects.[Name] = 'MisterPositive' And sys.schemas.name = 'Developers'
So yours would be
If Not Exists ( Select 1 from sys.objects
Inner join sys.schemas ON sys.objects.schema_id = sys.schemas.schema_id
where sys.objects.[Name] = 'YOURTABLE' And sys.schemas.[Name] = 'tSQLt' )
Begin
-- create table here
End

Related

Retrieve definition of Sequence object in SQL Server

How can I get the definition of any Sequence objects in SQL Server? For instance if I want to get the definition of View/Function/Procedure I would use below query
SELECT OBJECT_DEFINITION(tab.OBJECT_ID)
FROM SYS.OBJECTS tab
WHERE tab.[type] = 'V' /*FOR VIEW*/
SELECT OBJECT_DEFINITION(tab.OBJECT_ID)
FROM SYS.OBJECTS tab
WHERE tab.[type] = 'P' /*FOR PROCEDURE*/
SELECT OBJECT_DEFINITION(tab.OBJECT_ID)
FROM SYS.OBJECTS tab
WHERE tab.[type] = 'TR' /*FOR TRIGGER*/
Please let me know if we have similar options available to get the details for Sequence objects
A SEQUENCE doesn't have the same type of definition as an object like a VIEW or PROCEDURE, however, you could generate your own:
CREATE SEQUENCE dbo.YourSEQUENCE
START WITH 7
INCREMENT BY 4;
GO
SELECT NEXT VALUE FOR dbo.YourSEQUENCE;
GO
SELECT *
FROM sys.sequences
GO
SELECT CONCAT(N'CREATE SEQUENCE ' + QUOTENAME(s.[name]) + N',' + QUOTENAME(sq.[name]),NCHAR(13) + NCHAR(10),
N' START WITH ',CONVERT(int,sq.start_value), NCHAR(13) + NCHAR(10),
N' INCREMENT BY ',CONVERT(int,sq.increment),N';')
FROM sys.schemas s
JOIN sys.sequences sq ON s.schema_id = sq.schema_id
WHERE s.[name] = N'dbo'
AND sq.[name] = N'yourSEQUENCE';
GO
DROP SEQUENCE dbo.YourSEQUENCE;
If this is so you have a repository of all your definitions, that should already be in your Source Control Software.
Your Above Query is right.....
i.e.'V' -- FOR VIEW
'P' -- FOR PROCEDURE
'TR' -- FOR TRIGGER
SELECT sm.object_id, OBJECT_NAME(sm.object_id) AS object_name, o.type, o.type_desc, sm.definition
FROM sys.sql_modules AS sm
JOIN sys.objects AS o ON sm.object_id = o.object_id
ORDER BY o.type;
Use this Query...you will get all the data in single set just refer type Column Name.
Objects of type P, RF, V, TR, FN, IF, TF, and R have an associated SQL
module.
The SQL Server Database Engine assumes that object_id is in the current database context.
The collation of the object definition always matches that of the calling database context.
OBJECT_DEFINITION applies to the following object types:
C = Check constraint
D = Default (constraint or stand-alone)
P = SQL stored procedure
FN = SQL scalar function
R = Rule
RF = Replication filter procedure
TR = SQL trigger (schema-scoped DML trigger, or DDL trigger at either the database or server scope)
IF = SQL inline table-valued function
TF = SQL table-valued function
V = View
For better info ...use this link...
https://learn.microsoft.com/en-us/sql/relational-databases/system-catalog-views/sys-sql-modules-transact-sql?view=sql-server-ver15

Find and replace content in stored procedures ms sql server

I want to rename tables and views which are used in stored procedures. Is there any way to find and replace table names in stored procedures, maybe there is tool for ms sql server (i'm using ms sql server 2012).
SQL Server might not allow you to directly UPDATE the object definitions (Views and Stored Proceduress in your case) present in the System catalogs even after setting the 'Allow Updates' option to 1.
The following code will generate the required ALTER Script and you can run them manually after reviewing the definitions ([ModifiedDefinition] )or u can loop through each value of [ModifiedDefinition] and run it using sp_executesql.
SELECT
b.Name AS [ObjectName],
CASE WHEN b.type ='p' THEN 'Stored Procedure'
WHEN b.type ='v' THEN 'View'
ELSE b.TYPE
END AS [ObjectType]
,a.definition AS [Definition]
,Replace ((REPLACE(definition,'OLD Value','New Value')),'Create','ALTER') AS [ModifiedDefinition]
FROM sys.sql_modules a
JOIN
( select type, name,object_id
from sys.objects
where type in (
'p' -- procedures
,'v'--views
)
and is_ms_shipped = 0
)b
ON a.object_id=b.object_id
And as always, be careful with production data and take backups before performing bulk changes on object definitions!!
You can use DBvisualizer .. it pretty much works with all databases and with ms sql too, you can do all you mentioned by using this.
I answered this on another topic (https://stackoverflow.com/a/67728039/11165834) , I do it using the following script:
DECLARE #queryDef NVARCHAR(max)
WHILE EXISTS (
SELECT 1
FROM sys.sql_modules sm
JOIN sys.objects o ON sm.object_id = o.object_id
WHERE sm.definition LIKE '%TEXT_TO_REPLACE%'
AND o.type = 'V'
)
BEGIN
-- TO ALTER THE VIEW AUTOMATICALLY
SET #queryDef = ( SELECT TOP 1 Replace (Replace (sm.definition, 'CREATE VIEW', 'ALTER VIEW'),
'TEXT_TO_REPLACE',
'NEW_TEXT')
FROM sys.sql_modules sm
JOIN sys.objects o ON sm.object_id = o.object_id
WHERE sm.definition LIKE '%TEXT_TO_REPLACE%'
AND o.type = 'V')
EXEC (#queryDef)
END
I use it to replace procedures/views when I restore a backup from production into tests databases.
As #S.A said, be verry careful because is not a verry safe way.
Change the "o.type" and "Replace (sm.definition, 'CREATE VIEW', 'ALTER VIEW'" accordingly to your need

Update statement with nontouchable field

I have mssql2008 r2 sql server
The problem:
User has some column permissions on the table. He could update some of the columns of the table (not all). We need to create UPDATE statement so that it will not violate permissions.
Preferably without dynamic query.
Is there this ability in MSSQL server?
Without dynamic SQL (or dynamic query construction in the app or API layer)? I don't think it will be very pretty. The UPDATE command doesn't have any inherent knowledge of what permissions the user might have on the affected column(s). It is going to submit the query to the engine and hope for the best. If the user doesn't have permissions on all the columns, it's going to return an error, not try to circumvent that by altering the intended statement. I think this would actually be a very bad thing to continue with the update even though not all intended columns have been updated.
That all said, I suppose you could do something like this, but it is not going to be pretty at all - in fact it will be a lot easier if you are not relying on database principals:
DECLARE
#dpid INT = DATABASE_PRINCIPAL_ID(),
#obj INT = OBJECT_ID('dbo.foo'),
#col SYSNAME = N'bar';
UPDATE dbo.foo SET bar = CASE
WHEN EXISTS -- check they've been granted UPDATE at column or table level:
(
SELECT 1
FROM sys.database_permissions AS dp
INNER JOIN sys.objects AS o
ON dp.major_id = o.[object_id]
LEFT OUTER JOIN sys.columns AS c
ON dp.minor_id = COALESCE(c.column_id, 0)
WHERE dp.grantee_principal_id = #dpid
AND o.[object_id] = #obj
AND (c.name = #col OR c.column_id IS NULL)
AND dp.[permission_name] = 'UPDATE'
AND dp.[state] = 'G' -- GRANT
)
AND NOT EXISTS -- since DENY trumps GRANT, make sure that doesn't also exist:
(
SELECT 1
FROM sys.database_permissions AS dp
INNER JOIN sys.objects AS o
ON dp.major_id = o.[object_id]
LEFT OUTER JOIN sys.columns AS c
ON dp.minor_id = COALESCE(c.column_id, 0)
WHERE dp.grantee_principal_id = #dpid
AND o.[object_id] = #obj
AND (c.name = #col OR c.column_id IS NULL)
AND dp.[permission_name] = 'UPDATE'
AND dp.[state] = 'D' -- DENY
)
THEN #bar ELSE bar END
-- WHERE...
;
This isn't exactly what you're asking for; technically it updates the column but sets it to itself (so it will still be indicated as an updated column in a trigger, for example) but it prevents the input from being applied to the table. I also did not check against permissions granted in ways other than an explicit GRANT UPDATE or DENY UPDATE to the specified user or role - for example GRANT ALL, or permissions inherited by AD group membership, can complicate this. Of course it is not going to be much fun at all to manage this if you have multiple columns to check.
You may want to add other conditionals to the WHEN clause, e.g. to avoid the check for dbo (who ) or users you want to explictly bypass the check, you could have:
CASE
WHEN DATABASE_PRINCIPAL_ID() = 1 THEN #bar
WHEN SUSER_SNAME = 'some_user' THEN #bar
WHEN (...stuff from above...)
ELSE bar
END
-- WHERE...
;

How can I get the 'External name' of a SQL CLR trigger?

I have created a SQL CLR trigger with the follow SQL:
GO
CREATE TRIGGER AuditAccountsTable
ON [dbo].[Accounts]
FOR INSERT,DELETE,UPDATE
AS
EXTERNAL NAME namespace.Triggers.AuditTrigger
I am trying to query:
select * from sys.triggers
Is there a way to find the: EXTERNAL NAME namespace.Triggers.AuditTrigger on the trigger from querying in the DB?
I can't be sure as I don't have a place to test this, but does the text column returned below get you close to what you're looking for?
select t.name, c.text
from sys.triggers t
inner join sys.syscomments c
on t.object_id = c.id
where t.type_desc = 'CLR_TRIGGER'
Unlike T-SQL "modules" such as Stored Procedures and Functions, the SQLCLR T-SQL wrapper objects do not have their CREATE statements stored in the database. This is why you cannot access them via sys.sql_modules, OBJECT_DEFINITION, or the deprecated-since-SQL-Server-2005-and-should-not-be-used sys.syscomments. This is why SQLCLR Stored Procedures and Functions need to have their parameter default values stored in sys.parameters
Instead, CREATE statements for SQLCLR T-SQL wrapper objects are inferred from meta-data, just like Indexes, Primary Keys, Foreign Keys, etc.
You can get all of the parts of the CREATE TRIGGER statement from the following query:
SELECT OBJECT_SCHEMA_NAME(st.[object_id]) AS [SchemaName],
st.[name] AS [TriggerName],
OBJECT_SCHEMA_NAME(st.parent_id) AS [ParentSchemaName],
OBJECT_NAME(st.parent_id) AS [ParentName],
st.is_instead_of_trigger,
SUBSTRING((
SELECT N', ' + ste.[type_desc]
FROM sys.trigger_events ste
WHERE ste.[object_id] = st.[object_id]
FOR XML PATH ('')
), 3, 500) AS [Actions],
QUOTENAME(sa.name) AS [AssemblyName],
QUOTENAME(sam.assembly_class) AS [AssemblyClass],
QUOTENAME(sam.assembly_method) AS [AssemblyMethod]
FROM sys.triggers st
INNER JOIN sys.assembly_modules sam
ON sam.[object_id] = st.[object_id]
INNER JOIN sys.assemblies sa
ON sa.[assembly_id] = sam.[assembly_id]
WHERE st.parent_class = 1; --- OBJECT_OR_COLUMN

Stored procedures and the tables used by them

Is there a way to know what are the tables used by one stored procedure by doing an SQL query?
Best regards, and thanks for the help.
P.S.: I'm using SQL Server 2005.
This article on TechRepublic
Finding dependencies in SQL Server 2005
describes a way to do that:
This tutorial will show how you can
write a procedure that will look up
all of the objects that are dependent
upon other objects.
Here is the code to create the system stored procedure for finding object dependencies:
USE master
GO
CREATE PROCEDURE sp_FindDependencies
(
#ObjectName SYSNAME,
#ObjectType VARCHAR(5) = NULL
)
AS
BEGIN
DECLARE #ObjectID AS BIGINT
SELECT TOP(1) #ObjectID = object_id
FROM sys.objects
WHERE name = #ObjectName
AND type = ISNULL(#ObjectType, type)
SET NOCOUNT ON ;
WITH DependentObjectCTE (DependentObjectID, DependentObjectName, ReferencedObjectName, ReferencedObjectID)
AS
(
SELECT DISTINCT
sd.object_id,
OBJECT_NAME(sd.object_id),
ReferencedObject = OBJECT_NAME(sd.referenced_major_id),
ReferencedObjectID = sd.referenced_major_id
FROM
sys.sql_dependencies sd
JOIN sys.objects so ON sd.referenced_major_id = so.object_id
WHERE
sd.referenced_major_id = #ObjectID
UNION ALL
SELECT
sd.object_id,
OBJECT_NAME(sd.object_id),
OBJECT_NAME(referenced_major_id),
object_id
FROM
sys.sql_dependencies sd
JOIN DependentObjectCTE do ON sd.referenced_major_id = do.DependentObjectID
WHERE
sd.referenced_major_id <> sd.object_id
)
SELECT DISTINCT
DependentObjectName
FROM
DependentObjectCTE c
END
This procedure uses a Common Table
Expression (CTE) with recursion to
walk down the dependency chain to get
to all of the objects that are
dependent on the object passed into
the procedure. The main source of data
comes from the system view
sys.sql_dependencies, which contains
dependency information for all of your
objects in the database.
Try sp_depends, although you should probably recompile the stored procedure to update the statistics in the database.
Look up sp_depends system stored proc.
I think that as long as the stored procedure and the tables are all in the same database then you can right click on the procedure in SSMS and click "View Dependencies". I don't know the query behind the dialog though...
As others indicated you can use the Dependancies stored procedures; however, in my experience and this was back on SQL Server 2000, the depandancies were not always reliable. In some cases they weren't being updated. You can always go to the sysComments table assuming your schema is not encrypted.
declare #crlfSearch varchar(max),#objectSearch varchar(max),#escapeSearch varchar(max)
set #crlfSearch=('%bid' + char(13)+'%')
set #objectSearch='%bid %'
set #escapeSearch ='%[[]Bid]%'
select distinct so.name
from syscomments sc
inner join sysobjects so
on sc.id=so.id
where text like #objectSearch or text like #crlfSearch
or text like #escapesearch
This query looks for three common cases you might have to add some but basically we find where the table name has a space after it, (This helps to limit cases where the table name is part of another table name), Has a return at the end of it, or is escaped within brackets.