I want to run SQL queries which retrieve from a database according to user input.
Lets assume there is a table named Queries and the fields of the table are Index, Query, Name.
query - select * from Student
name - GetStudents
Index - 1
When user clicks a button an index will be passed into the server and a query match with that index will be triggered. Assume there are no inputs into queries.
Lets say there are 5 rows in the table and when user pass 3,the third query will be run. When user pass 4 the fourth query will be run.
I think I can simply do this by storing the query as a string on table retrieving the query and run. But I'm not sure whether this workaround is efficient.
Please help me with these points.
Is this approach is okay or is there any better workaround that I can follow.
Is it okay to store query as a string in a table.
Is there any workaround that I can create Stored Procedures pragmatically using asp.net in SQL server management studio.
I'm using ASP.Net and SQL server.
Note that here I can't use Stored Procedures to do this task. Because there is another front-end where user can insert queries into table that I have mentioned above. User has no access to use SQL server management studio.
In theory, yes you certainly could store the query string and then use sp_executesql to run that particular query string.
However, CAUTION. If you have a front end that allows a user to write and submit a query then how are you sanitizing that input? Is there anything to prevent the user submitting 'DROP DATABASE' as the query or event introducing other SQL injection attacks?
A better approach would be to create the procedures (assuming that the activities are all standard tasks) and allowing the user to select which procedure to execute.
You could check the integrity of the dynamic select statement by executing it under the most restrictive security context (a dbuser that has readonly permissions). To take it a bit further, you could also wrap the dynamic select statement into an ever changing dynamic container/string (ever changing part + dynamic query + ever changing part) and suppress any errors that happen during the validation/integrity check.
You cannot rely solely on sanitization because you'll end up in a never-ending catching-up struggle.
use mydbxyz;
go
--create a readonly dbuser
create user readonlydbuser without login;
alter role db_datareader add member readonlydbuser;
alter role db_denydatawriter add member readonlydbuser;
go
--procedure to execute dynamic select (no cte, no variables, just selects)
create or alter procedure execute_simpleselect #sqlinput nvarchar(max) = null
with execute as owner
as
begin
set nocount on;
if nullif(#sqlinput, '') is null
begin
--nothing to execute
return;
end
--check if sql input is a valid/simple select query
declare #foocontrol tinyint;
declare #tblalias sysname = quotename(newid());
declare #sqlcheck nvarchar(max) = N'
select #var = 1;
begin transaction;
begin try
select top (0) #var = '+ #tblalias + '.mycol
from
(
select 1 as mycol
where exists
(
'
+ #sqlinput +
'
)
) as '+ #tblalias + N'
end try
begin catch
select #var = 2;
end catch
rollback transaction;
';
/*
create user readonlydbuser without login;
alter role db_datareader add member readonlydbuser;
alter role db_denydatawriter add member readonlydbuser;
*/
--catch errors
begin try
--change context to a readonlyuser
execute as user='readonlydbuser'; --if this dbuser does not exist, nothing executes
exec sys.sp_executesql #stmt = #sqlcheck, #params = N'#var tinyint output', #var = #foocontrol output;
end try
begin catch
--do nothing, suppress errors
end catch
revert;
--if #foocontrol is not 1, the query cannnot be executed (syntactically incorrect, violation under minimal permissions etc)
if isnull(#foocontrol, 2) = 2
begin
raiserror('what are you trying to do?', 16, 1);
return;
end
--change to the callers security context
exec as caller;
exec sys.sp_executesql #stmt = #sqlinput;
end
--test
exec execute_simpleselect #sqlinput = 'select * from sys.objects';
exec execute_simpleselect #sqlinput = 'create table dbo.testtbl(id int)';
exec execute_simpleselect #sqlinput = 'drop table dbo.tablexzy';
exec execute_simpleselect #sqlinput = 'select user_name()';
The caller of the procedure who is in database AAA:-
use AAA
exec BBB.dbo.ap_MyProc
The procedure being called which is in database BBB:-
use BBB
create procedure ap_MyProc as
print 'We want a way to return the database name AAA'
Any advice would be appreciated.
Well i can now answer my own question. We can exploit syslockinfo...
declare #db_name varchar(255)
select
#db_name = db_name(rsc_dbid)
from
master.dbo.syslockinfo
where
req_spid = ##SPID
and req_ownertype = 4 --"exSession"
and rsc_dbid <> db_id()
select #db_name = isnull(#db_name, db_name())
print #db_name
Works in SQL 2008 as well. :)
Can your stored procedure be edited? If yes, I think you can edit the stored procedures and add one more parameter for the database name.
And during calling the stored procedure, you should pass the db_name() into the new parameter, so that your stored procedure could know which database is calling it
DECLARE #ServerName varchar(50) = db_name()
EXEC [dbo].[SP] #newParams = #ServerName
Currently work with multiple servers and need to return the results in a table, how can I do?
I intend to get data from each bank and return all through a single procedure.
Example, caught available space of the server and return in table format.
You must be in .NET
First create the links to other server
Example:
USE [master]
GO
EXEC master.dbo.sp_addlinkedserver
#server = N'SecondServer',
#srvproduct=N'SQL Server' ;
GO
EXEC master.dbo.sp_addlinkedsrvlogin
#rmtsrvname = N'SecondServer',
#locallogin = NULL ,
#useself = N'True' ;
GO
Then you can create procedure that can query multiple server.
Example:
CREATE PROCEDURE procedureName
(
#dateFrom datetime,
#dateTo datetime
)
AS
BEGIN
SELECT * FROM CurrentServerName.DatabaseName.TableName
UNION
SELECT * FROM SecondServerName.DatabaseName.TableName;
END
EDIT
The final goal is to call a stored procedure hosted in sybase with input and output parameters from SQL Server 2008 via Linked Server
I think title is pretty clear.
My goal is to execute a stored procedure hosted in Sybase SQL Anywhere 8 in SQL Server 2008 through the linked server I already created.
Any SQL query made through the linked server is working.
In addition I was able to execute a function but I don't now how to get the return value like that
EXEC ('CALL "dbname"."procedurename"(''param1'', ''param2'', ''param3'')') AT LinkedServerAlias;
Thanks 4 all your help!
Mauro
can you use four part naming convention?
like
exec LinkedServerName.dbname.dbo.procedurename #param1, #param2, #param3
I was finally able to do it by calling
SELECT * FROM OPENQUERY([LinkedServer], 'SELECT "dbname"."spname"(#p1,#p2, #p3)')
I'll add comments and example as soon as I experiment it.
4 part object names are valid only for SQL Server linked servers.
You have to have your EXEC inside an OPENQUERY
SELECT * FROM OPENQUERY([LinkedServer], 'EXEC MyDB.MyScheme.MyProc.spname #p1, #p2, #p3')
Now, you can't parametrise OPENQUERY calls so you have use dynamic SQL
DECLARE #sql nvarchar(4000), #linkedsql nvarchar(4000)
SET #sql = 'EXEC MyDB.MyScheme.MyProc.spname ' + CAST(#p1value as int) + ...
SET #linkedsql = 'SELECT * FROM OPENQUERY(LinkedServer, ''' + #sql + ''')'
EXEC (#linkedsql)
I have SQL Server 2008 with a linked Sybase server and I am trying to execute a stored procedure on the Sybase server using OPENQUERY. If I have a stored proc that doesn't take parameters it succeeds fine. If I have a stored proc with parameters it fails. I even tried a very basic stored proc that only took an int an that still failed. Below is the syntax I am using:
select * from
OPENQUERY([LINKSERVER],'exec database.user.my_stored_proc ''AT'',''XXXX%'',''1111'',1')
Msg 7357, Level 16, State 2, Line 3
Cannot process the object "exec database.user.my_stored_proc 'AT','XXXX%','1111',1". The OLE DB provider "ASEOLEDB" for linked server "LINKSERVER" indicates that either the object has no columns or the current user does not have permissions on that object.
As the proc will execute just fine without parameters, I don't think it is a permission issue.
This worked for me,
SELECT * FROM OPENQUERY(LOCALSERVER, 'SET FMTONLY OFF EXEC snr.dbo.GetAllSignals #controlRunId = 25, #experimentRunId = 26')
I was creating temporary tables, and that's why i got access denied
Here is more info http://www.sommarskog.se/share_data.html#OPENQUERY
I create a sp that doesn't return any value and it doesn't work.
Your SP in mysql have to return a value!
for example I do this in "mysql":
CREATE DEFINER=`root`#`localhost` PROCEDURE `MyPro`(IN `Name` VARCHAR(50), IN `Id` INT, OUT `Result` INT)
MODIFIES SQL DATA
BEGIN
DECLARE Result INT;
SET Result = 0;
INSERT into MyTable (Id,Name) VALUES(Id,Name);
SELECT Result;
END
That "Id" and "Name" is input parameter and "Result" is output parameter
and create linked server in SQL SERVER and call it like this:
select * from openquery
(
Test,'call mydb.MyPro(''Name'',''16'', #P0);'
)
It works for me :D
Linked Servers and OPENQUERY, Gems to MS SQL Server...that are wolves in sheep clothing. I've found the following solutions to work when dealing with parameters
If the SP is basically just SELECT statements, the move the same to a VIEW and just pass SQL statements via OPENQUERY.
Build the OPENQUERY as a string and then use execute_sql.
You could also see if it works to precede exec with SET FMTONLY ON:
OPENQUERY([LINKSERVER],'SET FMTONLY ON; exec database.user.my_stored_proc ''AT'',''XXXX%'',''1111'',1')
If you try this and it works, you should probably Google FMTONLY+OPENQUERY to get an idea of what it means.
Try this,
SELECT * FROM OPENQUERY(linked_server_name, 'SELECT postgres_procedure_name (parameters)');
I experienced a very similar issue, but my SP wasn't taking any parameters.
I tried experimenting with altering the query sent through the openquery to include 'SET NOCOUNT ON' and 'SET FMTONLY OFF' but this had no difference.
The only solution that worked for my stored procedure was dropping the existing version, and altering the code to specifically 'SET NOCOUNT ON'
After doing this I was able to successfully run my stored proc through my linked server connection.
First of all you have to add hard code text fields then you have to
replace it by your parameters value like FromDate,TillDate,EmpID,CompCode,0,DeptID,DesgId,LocationID,AtnType
DECLARE #startdate varchar(255) = '2019-12-17'
DECLARE #enddate varchar(255) = '2019-12-17'
Set #SQL = 'SELECT * FROM OPENQUERY(' + quotename(#LinkedServer) + ',' + '''' +
'SET FMTONLY OFF; exec [TAP].[dbo].[GetAttendanceList] ' + 'FromDate,TillDate,EmpID,CompCode,0,DeptID,DesgId,LocationID,AtnType,1'')'
You have to replace your parameters values shown below
set #SQL=REPLACE(#SQL,'FromDate',+''''+''''+#startdate+''''+'''')
set #SQL=REPLACE(#SQL,'TillDate',+''''+''''+#enddate+''''+'''')
set #SQL=REPLACE(#SQL,'CompCode',+''''+''''+#CompCode+''''+'''')
set #SQL=REPLACE(#SQL,'AtnType',+''''+''''+''''+'''')
if #EmpID is Null
begin
set #SQL=REPLACE(#SQL,'EmpID','null')
end
if #DeptID is Null
begin
set #SQL=REPLACE(#SQL,'DeptID','null')
end
if #DesgId is Null
begin
set #SQL=REPLACE(#SQL,'DesgId','null')
end
if #LocationID is Null
begin
set #SQL=REPLACE(#SQL,'LocationID','null')
end
print #SQL
exec ( #SQL)