How to add Stored Procedures to Version Control - sql-server

Our team just experienced for the first time the hassle of not having version control for our DB. How can we add stored procedures at the very least to version control? The current system we're developing relies on SPs mainly.

Background: I develop a system that has almost 2000 stored procedures.
The critical thing I have found is to treat the database as an application. You would never open an EXE with a hex editor directly and edit it. The same with a database; just because you can edit the stored procedures from the database does not mean you should.
Treat the copy of the stored procedure in source control as the current version. It is your source code. Check it out, edit it, test it, install it, and check it back in. The next time it has to be changed, follow the same procedure. Just as an application requires a build and deploy process, so should the stored procedures.
The code below is a good stored procedure template for this process. It handles both cases of an update (ALTER) or new install (CREATE).
IF EXISTS(SELECT name
FROM sysobjects
WHERE name = 'MyProc' AND type = 'P' AND uid = '1')
DROP PROCEDURE dbo.MyProc
GO
CREATE PROCEDURE dbo.MyProc
AS
GO
However following sample is better in situations where you control access to the stored procedures. The DROP-CREATE method loses GRANT information.
IF NOT EXISTS(SELECT name
FROM sysobjects
WHERE name = 'MyProc' AND type = 'P' AND uid = '1')
CREATE PROCEDURE dbo.MyProc
AS
PRINT 'No Op'
GO
ALTER PROCEDURE dbo.MyProc
AS
GO
In addition, creating a process to build the database completely from source control can help in keeping things controlled.
Create a new database from source control.
Use a tool like Red Gate SQL Compare to compare the two databases and identify differences.
Reconcile the differences.
A cheaper solution is to simply use the "Script As" functionality of SQL Management Studio and do a text compare. However, this method is real sensitive to the exact method SSMS uses to format the extracted SQL.

I’d definitely recommend some third party tool that integrates into SSMS. Apart from SQL Source Control mentioned above you can also try SQL Version from Apex.
Important thing is to make this really easy for developers if you want them to use it and the best way is to use tool that integrates into SSMS.

2nd solution from #Darryl didn't work as suggested by #Moe. I modified #Darryl's template and I got it working, and thought it would be nice to share it with everybody.
IF NOT EXISTS(SELECT name FROM sysobjects
WHERE name = '<Stored Proc Name>' AND type = 'P' AND uid = '1')
EXEC sp_executesql N'CREATE PROCEDURE dbo.<Stored Proc Name>
AS
BEGIN
select ''Not Implemented''
END
'
GO
ALTER PROCEDURE dbo.<Stored Proc Name>
AS
BEGIN
--Stored Procedure Code
End
This is really nice because I don't lose my stored procedure permissions.

I think it's good to have each stored procedure scripted to a separate .sql file and then just commit those files into source control. Any time a sproc is changed, update the creation script - this gives you full version history on a sproc by sproc basis.
There are SQL Server source control tools that hook into SSMS, but I think they are just scripting the db objects and committing those scripts. Red Gate looks to be due to releasing such a tool this year for example.

We just add the CREATE statement to source control in a .sql file, e.g.:
-- p_my_sp.sql
CREATE PROCEDURE p_my_sp
AS
-- Procedure
Make sure that you only put one SP per file, and that the filename exactly matches the procedure name (it makes things so much easier to find the procedure in source control)
You then just need to be disciplined about not applying a stored procedure to your database that hasn't come from source control.
An alternative would be to save the SP as an ALTER statement instead - this has the advantage of making it easier to update an existing database, but means you need to do some tweaking to create a new empty database.

I've been working on this tool http://timabell.github.com/sqlHawk/ for exactly that purpose.
The way to ensure no-one forgets to check in their updated .sql files is by making your build server force the staging and live environments to match source control ;-) (which this tool will assist you with).

Related

SQL Server SQLCLR function receives parameter error after copying from one DB to another

I am trying to copy the send email assembly from one database to another. I clicked on script assembly as create to and created it in the new db.
When I try to send an email with the function in the newer db I get the following error:
The parameter 'fileName' cannot be an empty string. Parameter name: fileName
How can I copy the assembly across databases?
Some details:
Both DBs are on the same instance
Both DBs are owned by the same login
Using SQL Server 2016
Assembly is marked as UNSAFE in both DBs
Both DBs have TRUSTWORTHY enabled
T-SQL wrapper object is a scalar function / UDF
Function is being called the same way in both DBs
How can I copy the assembly across databases?
So far I am not seeing how this is a SQLCLR issue. You clearly copied the Assembly and the T-SQL wrapper object else you would be getting T-SQL errors instead of a .NET error.
I clicked on script assembly as create to and created it in the new db.
Given that you scripted out the T-SQL wrapper object and you are getting an error related to an input parameter, you might be running into a bug that causes defaults for NVARCHAR parameters to not script out correctly:
SSMS scripting CLR stored procedure NVARCHAR parameter NULL default as N'' (empty string)
Execute the following in both old and new DBs to make sure that all parameter definitions are the same, including any potential default values (paying close attention to rows that have a 1 for [has_default_value]):
SELECT [name], [user_type_id], [max_length], [is_output],
[has_default_value], [default_value]
FROM sys.parameters prm
WHERE prm.[object_id] = OBJECT_ID(N'dbo.ObjectName')
ORDER BY prm.[parameter_id];
If you find any differences, you will need to update your CREATE statement to include the correct default value(s). For example, if you have:
#SomeParam [nvarchar](1 - 4000) = N``
Then you will need to update that part of your T-SQL script to instead be:
#SomeParam [nvarchar](1 - 4000) = NULL
And then re-run the CREATE (you might need to either first DROP the existing T-SQL wrapper object, or change the CREATE to be ALTER).
Please vote for that Feedback bug report that I linked above. Thanks!
For more info on working with SQLCLR in general, please visit: SQLCLR Info

How do I execute a SQL Server stored procedure from Informatica Developer (10.1, not Power Center)

I am trying to execute (call) a SQL Server stored procedure from Infa Developer, I created a mapping (new mapping from SQL Query). I am trying to pass it runtime variables from the previous mapping task in order to log these to a SQL Server table (the stored procedure does an INSERT). It generated the following T-SQL query:
?RETURN_VALUE? = call usp_TempTestInsertINFARunTimeParams (?Workflow_Name?, ?Instance_Id?, ?StartTime?, ?EndTime?, ?SourceRows?, ?TargetRows?)
However, it does not validate, the validation log states 'the mapping must have a source' and '... must have a target'. I have a feeling I'm doing this completely wrong. And: this is not Power Center (no sessions, as far as I can tell).
Any help is appreciated! Thanks
Now with the comments I can confirm and answer your question:
Yes, Soure and Target transformations in Informatica are mandatory elements of the mapping. It will not be a valid mapping without them. Let me try to explain a bit more.
The whole concept of ETL tool is to Extract data from the Source, do all the needed Transformations outside the database and Load the data to required Target. It is possible - and quite often necessary - to invoke Stored Procedures before or after the data load. Sometimes even use the exisitng Stored Procedures as part of the dataload. However, from ETL perspective, this is the additional feature. ETL tool - here Informatica being a perfect example - is not meant to be a tool for invoking SPs. This reminds me a question any T-SQL developer asks with his first PL-SQL query: what in the world is this DUAL? Why do I need 'from dual' if I just want to do some calculation like SELECT 123*456? That is the theory.
Now in real world it happens quite often that you NEED to invoke a stored procedure. And that it is the ONLY thing you need to do. Then you do use the DUAL ;) Which in PowerCenter world means you use DUAL as the Source (or actually any table you know that exists in the source system), you put 1=2 in the Source Filter property (or put the Filter Transforation in the mapping with FALSE as the condition), link just one port with the target. Next, you put the Stored Procedure call as Pre- or Post-SQL property on your source or target - depending on where you actually want to run it.
Odd? Well - the odd part is where you want to use the ETL tool as a trigger, not the ETL tool ;)

Why script generated by SSMS shown in red is different from script stored in system tables

Why script generated by SSMS shown in red is different from script stored in system tables. Please notice stored procedure names in query, query result and Object explorer.
i.e.
All these methods are giving me same script
sql_module
object_definition
sp_helptext
However when generated from SSMS, right click -> script as Create or Modify is giving a different script.
How is it possible and generating different scripts.
The answer can be confusing.
The Stored procedure getBudgets4programManager2 was renamed (very likely using sp_rename https://msdn.microsoft.com/en-us/library/ms188351.aspx), so the original definition does not match the new name. BTW. Notice that the definition stored in metadata will always change the DDL command to CREATE in case of issuing an ALTER PROCEDURE statement.
At the same time, SSMS scripting features will not simply get the definition from metadata as it has an object representation of the stored procedure, it will normalize the schema name & object name, and it may also normalize the DDL command accordingly (CREATE/ALTER). Notice that the schema is showing it is normalized (i.e. [dbo]), and that the current name is also normalized.
As for why the metadata definition is not renamed at the same time you rename the object. The answer is not 100% clear, but such change would affect any features in the SQL Server engine that relies on the definition, including using the WITH ENCRYPTION option on ALTER/CREATE PROCEDURE as well as the verification of digital signatures.
As far as I know, other elements in both versions of the scripts should remain intact (comments, blank spaces, etc.).
I hope this information helps.

SQL - How to check if altering a table will break any stored procedures

Is there a nice way before I alter a table (e.g. remove a column), to see if that this will break any stored procedures?
I am trying to do this in MS SQL Server
Use the query here to search all stored procedures for the table and column name. You will probably still want to look at the code for each one you find to verify that it will or won't break.
you can use the following query to search for the table name in any stored procedures:
SELECT name
FROM sys.procedures
WHERE Object_definition(object_id) LIKE '%Your_Table_Name%'
I suggest you:
Make sure you have a separate environment (DEV)
Use the sample code from here to create a proc that confirms all objects in the database can be recompiled
How to Check all stored procedure is ok in sql server?
Use it - I can guarantee you will already have failing objects before you remove your column
Remove your column and use it again to see if more things broke
The more mature approach to this is to put your database into a database project and build that. But you can't do this until your database is valid.

Hide Store Procedures

Is there any way that we can Hide Store Procedures in SQL Server from users?
For SQL Server 2005 and above, don't give them permissions. Then, "Metadata visibility" means it's not visible and not runnable. It makes no sense to want to hide them but give them permissions.
Note: db_owners and syadmins will always see them.
Otherwise your only option is to encrypt the stored procedure as mentioned (which is easily defeated using free tools).
You can encrypt the text of the stored procedure, if that is what you mean.
CREATE PROCEDURE my_procedure
WITH ENCRYPTION
AS
BEGIN
SELECT *
FROM my_table
END
The encryption is not unbreakable, but at least it is a first line of defence.

Resources