Injection SQL Dynamic Stored Procedure - sql

Recently, I started learning and I have a question.
Please advice , is the below SQL stored procedure protected from ( injection , hack ,  ... )  and it is safe to use it  ?
Alter Proc spGetEmployeesByDepartment
#DepartmentName nvarchar(50)
As
Begin
Declare #sql nvarchar(max)
set #sql = ' Select E.ID , E.Name , E.Salary ,D.DepartmentName ,E2.Name as ManagerName
From tblEmployee E
left join tblDepartment D
On E.DepartmaintID = D.ID
Left join tblEmployee E2
On E.managerID = E2.ID
Where 1=1'
if(#DepartmentName is not null )
Set #sql = #sql + ' and D.DepartmentName = #DepName'
Execute sp_executesql #sql,
N'#DepName nvarchar(50)',
#DepName = #DepartmentName
End
Execute spGetEmployeesByDepartment #DepartmentName ='IT'

Related

Stored procedure not return data while where condition as parameter

ALTER PROCEDURE procGetData
#companyid INT,
#condition NVARCHAR(MAX)
AS
BEGIN
DECLARE #cond NVARCHAR
DECLARE #sql NVARCHAR
SELECT #sql = 'select e.id, e.code, e.firstname + isnull('' ''+e.lastname,'''') [name],
from hrm_employee e
inner join (select max(id) [id], hrm_employeeid from hrm_employeeservice group by hrm_employeeid) ser on ser.hrm_employeeid = e.id
inner join hrm_gender g on e.genderid = g.id and g.companyid = '+CONVERT(NVARCHAR,#companyid)+'inner join hrm_maritalstatus m on e.maritalstatusid=m.id and m.companyid='+CONVERT(NVARCHAR,#companyid)+'
where '+#cond
EXEC (#sql)
END
The selected values(id,code,name) are not get while exec this stored procedure from C# using sqlAdapter
#cond variable is declared but never assigned and this means that the supplied parameter "#condition" is not used in the stored procedure at all.
It is bad bad practice (SQL Injection) to have where clause passed in as parameter. I completely agree with Larnu & marc_s on the coding practice.

SQL Query UNION with inner Join / left join

im stuck with some "simple" sql query.
I want to query all DB's and get all sql-users back.
first i used the sp_foreachdb, but than read its not supported and also the output is not the best for further handling...
DECLARE #command varchar(1000)
SELECT #command = 'USE [?]
IF DB_ID(''?'') > 4
SELECT ''?'' as DBName, * FROM sysusers AS SU
Left Join sys.server_principals AS SP
ON SU.sid = SP.sid
WHERE SP.type = ''S''
ORDER BY SU.name'
EXEC sp_MSforeachdb #command
Now i get bit further with nested queries and UNION.
But now i get all users and not only the sql users (not system-users)
DECLARE #Sql NVARCHAR(MAX) = NULL;
SELECT #Sql = COALESCE(#Sql + ' UNION ALL ' + CHAR(13) + CHAR(10), '' ) + 'SELECT ''' + DB.[name] + ''' AS dbname, SU.[name] COLLATE Latin1_General_CI_AS AS Username
FROM ' + QUOTENAME([name]) + '.sys.sysusers AS SU'
--INNER Join sys.server_principals AS SP'
--ON SU.sid = SP.sid
--WHERE SP.type = ''S''
--ORDER BY SU.name'
FROM master.sys.databases as DB
WHERE [database_id] > 4 AND [state] = 0;
SET #Sql = ' ' + #Sql;
--PRINT #Sql;
EXECUTE ( #Sql )
As soon as i add the commented lines back, there is an error with the "next to union statement"...
Can anyone show me how to correct use a "for each database" query? :)
Thx alot.

TSQL - Changing databases dynamically

I'm in a new company, and trying to write a proc that loops through the databases and looks up a keyword in all the tables, procs, etc.
It works great in theory, however I've noticed that the database never changes.
I've outputted the SQL, and ran it, no problem. But if I run the piece of code, it doesn't change.
I've also played around with the code and hard-coded the table name and gotten it to work, so could it be a security feature?
Here's the TSQL:
Declare #Dbname varchar(250); --Stores Database Name<br>
Declare #SearchTerm varchar(250); --What we're searching the DB for<br>
Declare #vSQL varchar(550)=''; --Variable that will hold our dynamic queries<br>
set #SearchTerm='LoadID'; <br>
select name
from sys.databases
where owner_sid != 0x01;
print #Dbname;
set #vSQL = 'use [' + #dbname + ']';
exec (#vSQL);
--exec #vSQL;
--execute (#vSQL);
--execute #vSQL);
EXEC runs in its own context. Put entire script into #vSql kind of
set #vSQL = 'use [' + #dbname + '];' +'--do what you need ' ;
Something I have that does this, and a bit more is the following proc. Should loop through all DB's on a given instance, look for a keyword in the definition of objects in those dbs, as well as if any jobs make use of those objects and their last execute duration.
USE [master]
GO
Create Proc dbo.DependencyCheck #SearchKey Varchar(150) As
Begin
--DB Refs
Drop Table If Exists #Databases
Create Table #Databases
(
DatabaseName Varchar(50) Primary Key
,Checked Int Default 0 Not Null
,SearchKey Varchar(150)
,DependencyText As 'Insert Into #Dependencies
Select Distinct '
+ '''' + DatabaseName + '''' +
',
D.id As ObjectID,
O.name As ObjectName,
xtype As ObjectType,
S.name As SchemaName
From '
+ DatabaseName + '.dbo.syscomments D
Inner Join ' + DatabaseName + '.dbo.sysobjects O
On O.ID = D.id
Inner Join ' + DatabaseName + '.sys.schemas As S
On s.schema_id = O.uid
Where D.text Like ''%' + SearchKey + '%'''
)
Insert Into #Databases (DatabaseName, SearchKey)
Select
Name, #SearchKey
From sys.sysdatabases As S
Where S.filename Not Like '%.SS' --Not DB Snapshots
Declare #TargetDatabase Varchar(25) = (Select Top 1 DatabaseName From #Databases As D Where D.Checked = 0)
--Dependency Table
Drop Table If Exists #Dependencies
Create Table #Dependencies
(
DatabaseName Varchar(50) Not Null,
ObjectID Int Not Null,
ObjectName Varchar(150) Not Null,
ObjectType Varchar(15) Not Null,
SchamaName Varchar(150) Not null
)
--Dynamic SQL for Insert
Declare #DynamicDependency Varchar(8000) = (Select D.DependencyText From #Databases As D Where D.DatabaseName = #TargetDatabase)
While #TargetDatabase Is Not Null
Begin
Exec(#DynamicDependency)
Update D Set Checked = 1 From #Databases D Where DatabaseName = #TargetDatabase
Set #TargetDatabase = (Select Top 1 DatabaseName From #Databases As D Where D.Checked = 0)
Set #DynamicDependency = (Select D.DependencyText From #Databases As D Where D.DatabaseName = #TargetDatabase)
End
;With JobStats As
(
Select Distinct
J.name,
JH.step_id,
First_Value(JH.run_duration) Over (Partition By J.name, JH.step_id Order By CA.StartTime Desc) As Last_Duration,
Avg(JH.run_duration) Over (Partition By J.name, JH.step_id) As Avg_Duration
From msdb.dbo.sysjobhistory As JH
Cross Apply (Select Convert(Datetime, Convert(varchar(8),run_date))
+ Convert(datetime, Stuff(STUFF(RIGHT(REPLICATE('0', 6) + CAST(run_time as varchar(6)), 6), 3, 0, ':'), 6, 0, ':')) As StartTime) CA
Inner Join msdb.dbo.sysjobs As J
On J.job_id = JH.job_id
Where JH.step_id <> 0
And JH.run_status = 1 -- Success
)
Select
D.ObjectID
,D.DatabaseName
,D.SchamaName
,D.ObjectName
,D.ObjectType
,J.name As JobName
,JS.step_id As JoBStepID
,JS.step_name As JobStepName
,JStat.Last_Duration
,JStat.Avg_Duration
From #Dependencies As D
Left Join msdb.dbo.sysjobsteps JS
On JS.command Like '%' + D.ObjectName + '%'
And JS.subsystem = 'TSQL'
Left Join msdb.dbo.sysjobs J
On J.job_id = JS.job_id
Left Join JobStats JStat
On JStat.name = J.name
And JStat.step_id = JS.step_id
Order By 1, 3
End

How can I retrieve all the stored procedures and their input and output parameters in all the databases from SQL Server?

Apologies, for a convoluted question - I'm not a dba. Is there a simple script I can run that can list all the stored procedures I have on SQL Server, grouped by database and list them with the input and output parameters that go with the stored procedures.
I'm writing a similar script outside of SQL, to do the same for a language calling the stored procedures, so I find if there are conflicts in a legacy application.
Use the following script:
DECLARE #CurrentRowID INT
,#CurrentDatabase SYSNAME;
DECLARE #DynamicSQL NVARCHAR(MAX);
IF OBJECT_ID('tempdb..##DataSource') IS NOT NULL
BEGIN
DROP TABLE ##DataSource;
END;
CREATE TABLE ##DataSource
(
[database] SYSNAME
,[procedure] SYSNAME
,[parameter] SYSNAME
,[is_output] BIT
);
DECLARE #DataBases TABLE
(
[RowID] INT IDENTITY(1,1)
,[database] SYSNAME
);
INSERT INTO #DataBases ([database])
SELECT [name]
FROM [sys].[databases];
WHILE EXISTS(SELECT 1 FROM #DataBases)
BEGIN
SELECT TOP 1 #CurrentRowID = [RowID]
,#CurrentDatabase = [database]
FROM #DataBases;
SET #DynamicSQL = N'INSERT INTO ##DataSource
SELECT ''' + #CurrentDatabase + ''' AS [database]
,PR.[name]
,P.[name]
,P.[is_output]
FROM [' + #CurrentDatabase + '].[sys].[procedures] PR
INNER JOIN [' + #CurrentDatabase + '].[sys].[parameters] P
ON PR.[object_id] = P.[object_id]'
EXEC sp_executesql #DynamicSQL;
DELETE FROM #DataBases
WHERE [RowID] = #CurrentRowID;
END;
SELECT *
FROM ##DataSource
Of course, you can filter some of the databases, or add more columns from the sys.procedures dmv like system type for example.
Run a loop/cursor on sys.databases and inside the loop, USE and run the following query and keep taking union:
SELECT pr.name [Procedure], par.name Parameter, CASE WHEN is_output = 1 THEN 'Output Parameter' ELSE 'Input Parameter' END [ParameterType]
FROM sys.parameters par
INNER JOIN sys.procedures pr ON pr.object_id = par.object_id
ORDER BY [Procedure], [ParameterType]
This will give you all procedures and their dependent parameters.
declare #sql nvarchar(max) = ''
set #sql = #sql + N'union all
select '''+ quotename(d.name) + N''' as db, s.name as sname, p.name as p.name, r. name as paramname, r.is_output as paramoutput
from '''+ quotename(d.name) + N'''.sys.procedures p
join sys.parameters r on p.object_id = r.object_id
join sys.schemas s on p.schema_id = s.schema_id'
from sys.databases d
-- where d.name like ....
order by d.name
set #sql = stuff#sql, 1, 10, N'')
exec sp_executesql #sql
-- not tested

How to get Row count by dynamically passing the table name

create procedure qa_cc
#tablename varchar(500)
AS
BEGIN
-- Create two integer values
DECLARE #tableOneCount varchar(50), #tableTwoCount varchar(50)
-- Get the number of rows from the first table
SELECT #tableOneCount = 'SELECT COUNT(*) FROM' + #tablename;
exec (#tableOneCount);
select #tableOneCount ;
END
exec qa_cc #tablename=table1
You could use sp_executesql, like:
declare #sql nvarchar(max);
set #sql = N'select #cnt = count(*) from ' + #tablename;
declare #cnt int;
exec sp_executesql #sql, N'#cnt int output', #cnt = #cnt output;
select #cnt;
SELECT SUM(pa.rows) RowCnt
FROM sys.tables ta
INNER JOIN sys.partitions pa
ON pa.OBJECT_ID = ta.OBJECT_ID
WHERE ta.is_ms_shipped = 0 AND pa.index_id IN (1,0)
and ta.name=#tablename
GROUP BY ta.name
See http://blog.sqlauthority.com/2010/09/08/sql-server-find-row-count-in-table-find-largest-table-in-database-part-2/
Looks like you were missing a space after the FROM keyword which was reading FROMTABLE rather than FROM Table
DECLARE #TABLE NVARCHAR(100)
SET #TABLE = 'CLIENT' -- YOUR TABLE NAME
EXEC('SELECT COUNT(*) FROM ' + #TABLE)
CREATE PROCEDURE [dbo].[TableRowCount]
#tableName text
AS
EXEC ('SELECT COUNT(*) FROM ' + #tableName)
RETURN ##ROWCOUNT
I hope that helps. Thank you.