Particular query causes ADO Recordset to fail with E_FAIL - sql-server-2005

i'm trying to run (two) queries against SQL Server 2005 using ADO:
SELECT
sp.nt_username AS NTUsername,
sp.hostname AS HostName
FROM sys.dm_tran_locks tl
INNER JOIN master.dbo.sysprocesses sp
ON tl.request_session_id = sp.spid
WHERE tl.resource_type = N'APPLICATION'
AND tl.resource_database_id = (
SELECT dbid
FROM master.dbo.sysprocesses
WHERE spid = ##spid)
and the SQL Server 2000 compatible version:
SELECT
sp.nt_username AS NTUsername,
sp.hostname AS HostName
FROM master.dbo.syslockinfo sli
INNER JOIN master.dbo.sysprocesses sp
ON sli.req_spid = sp.spid
WHERE rsc_type = 10 --10=Appliction
AND rsc_dbid = (
SELECT dbid
FROM master.dbo.sysprocesses
WHERE spid = ##spid)
The query executes fine:
IRecordset rs =new Recordset();
rs.CursorLocation = adUseClient; //the default for a Recordset is adUseServer (Connection.Execute's default is adUseClient)
rs.CursorType := adOpenForwardOnly; //the default
rs.Open(szQuery, conn.ConnectionObject,
adOpenForwardOnly, //CursorType
adLockReadOnly, //LockType
adCmdText);
But then checking the status of BOF or EOF:
if (rs.EOF) then
triggers an exception:
HRESULT: 0x80004005 (Unspecified error)
Error message: "Data provider or other service returned an E_FAIL status"
What is about this query that causes ADO to fail so miserably?
Note: There really is a matching row:
The provider i'm using in the connection string is Provider=SQLOLEDB.
Bonus Chatter:
sysprocesses
nt_username nchar(128)
hostname nchar(128)
and querying for both - but one at a time - works, e.g.:
SELECT
sp.nt_username AS NTUsername
and
SELECT
sp.hostname AS HostName
work. Querying for both fail.

i found the problem. It's a known issue with SQL Server 2005 and ADO:
Even though nt_username and hostname already are nchar(128), you need to manually cast them to nchar(128)
SELECT
CAST(sp.nt_username AS nchar(128)) AS NTUsername,
CAST(sp.hostname AS nchar(128)) AS HostName
FROM sys.dm_tran_locks tl
INNER JOIN master.dbo.sysprocesses sp
ON tl.request_session_id = sp.spid
WHERE tl.resource_type = N'APPLICATION'
AND tl.resource_database_id = (
SELECT dbid
FROM master.dbo.sysprocesses
WHERE spid = ##spid)
There is also a known bug with SQL Server 2005 and ADO and the use of ##spid in a query; you cannot do it. Fortunately i can, in this case, use DB_ID():
SELECT
CAST(sp.nt_username AS nchar(128)) AS NTUsername,
CAST(sp.hostname AS nchar(128)) AS HostName
FROM sys.dm_tran_locks tl
INNER JOIN master.dbo.sysprocesses sp
ON tl.request_session_id = sp.spid
WHERE tl.resource_type = N'APPLICATION'
AND tl.resource_database_id = DB_ID()
Bada-bing.
SQL Server 2005 bug.
It might still exist in SQL Server 2008, SQL Server 2008 R2, SQL Server 2012

Related

Invalid SQL statement; error when using IF EXISTS() in SQL statement, OLEDB MS ACCESS

I'm trying to build an SQL statement that will insert or update a row in the database depending on whether it exists in the table already. This format seems to work when I interface to an MSSQL server, but does not work when I use an OLEDB connection to MS Access.
IF EXISTS(select * from Resistors where ID = 2816)
update Resistors set
[Part Number]='1234'
where ID = 2816
else
insert into Resistors (
[Part Number]
)
values(
'1234'
)
;
I have validated these two sql commands using the OLEDB connection to MS Access. They work properly but now with the IF EXISTS() portion of the command.
update Resistors set
[Part Number]='1234'
where ID = 2816
insert into Resistors (
[Part Number]
)
values(
'1234'
)
The IF EXISTS() statement appears to match other documentation I have seen on the internet but I must be doing something wrong.
This is the error I receive when I run the command.
Invalid SQL statement; expected 'DELETE', 'INSERT', 'PROCEDURE', 'SELECT', or 'UPDATE'.
This is my connection string
connection.ConnectionString = "Provider = Microsoft Office 12.0 Access Database Engine OLE DB Provider; Data source = " + _database_path;
Is the exists command not supported by this connection interface? Is there a version that supports the exists command?
Unfortunately, ifexists() is not supported in MS-Access sql.
you can use select count() as a work around, if returns 0 then it is not exist.
...
string cmdstr = "SELECT COUNT(*) FROM Resistors where ID = 2816";
....
int count = (int)command.ExecuteScalar();
....
if (count=0)
....
I hope this may help

SSIS - OLEDB Source - how to use sql query with variables?

I have this query that I want to export its contents to a table:
DECLARE #bdname VARCHAR(50)
SET #bdname = ?
SELECT
#bdname,
CONVERT(CHAR(30), dp2.name),
CONVERT(CHAR(20), dp.name)
FROM
sys.database_principals AS dp
INNER JOIN
sys.database_role_members AS drm ON dp.principal_id = drm.role_principal_id
INNER JOIN
sys.database_principals AS dp2 ON drm.member_principal_id = dp2.principal_id
WHERE
(dp2.principal_id > 4) AND (dp2.type <> 'R')
If I put this as part of a Execute SQL Task, it goes ok, but I can't (don't know how) then map the results into something that I can export to a SQL table.
Can anyone guide me on how can I put the results of this query into a table? It's because if I use dataflow and ole db source, it does not accept this type of query.
Any help would be much appreciated.
Thanks
Add a dataflow task, inside it add an Oledb source and an Oledb destination.
Add a variable of type string , set Evaluate as expression to true and assign the following expression:
"SELECT '" + #[User::bdname] + "' , convert(char(30),dp2.name), convert(char(20),dp.name)
FROM sys.database_principals AS dp INNER JOIN
sys.database_role_members AS drm ON dp.principal_id = drm.role_principal_id
INNER JoIN
sys.database_principals AS dp2 ON drm.member_principal_id = dp2.principal_id
WHERE (dp2.principal_id > 4) AND (dp2.type <> 'R')"
(Assuming bdname value is stored in user::bdname variable)
In the Oledb source set the source type to Sql command from variable and choose the created variable
Map the oledb source to the oledb destination
UPDATE 1
After reading your comment "...This foreach loop will query the sys.databases for all the user databases, and it is supposed to iterate that variable, to get the permissions".
To iterate over databases you have to add an Execute SQL Task with an SQL Command
SELECT name from sys.databases
and set the Result Set to Full Result Set , and assign the Result Set to a variable of type Object
Link this Execute SQL Task to the ForEach Loop Container
In the foreach Loop Container change the enumerator type to Ado enumerator and choose the object variable as source
Also don't forget to set the Dataflow task Delay Validation property to True
UPDATE 2 (workaround)
Try joining your query with sys.databases instead of using Foreach loop container (i don't know if it achieve what you want to do)
SELECT db.name, convert(char(30),dp2.name), convert(char(20),dp.name)
FROM sys.database_principals AS dp INNER JOIN
sys.database_role_members AS drm ON dp.principal_id = drm.role_principal_id
INNER JoIN
sys.database_principals AS dp2 ON drm.member_principal_id = dp2.principal_id
INNER JOIN sys.databases as db ON db.owner_sid = dp2.sid
WHERE (dp2.principal_id > 4) AND (dp2.type <> 'R')

Query to get the information of Databases used by Stored Procedure in SQL server 2005

Is there any query in SQL server 2005 that returns the list of Stored procedures in the particular database along with the name of databases whose objects are getting used in the stored procedure.
That is how to get all procedure names:
select *
from DatabaseName.information_schema.routines
where routine_type = 'PROCEDURE'
I will check now, if there is any way to check their code for table names.
you can use this query
it will show all dependencies even to the columns
SELECT
--SP, View, or Function
ReferencingName = o.name,
ReferencingType = o.type_desc,
--Referenced Field
ref.referenced_database_name, --will be null if the DB is not explicitly called out
ref.referenced_schema_name, --will be null or blank if the DB is not explicitly called out
ref.referenced_entity_name,
ref.referenced_minor_name
FROM sys.objects AS o
cross apply sys.dm_sql_referenced_entities('dbo.' + o.name, 'Object') ref
where o.type = 'p'
-- for other database object types use below line
-- o.type in ('FN','IF','V','P','TF')
works for single database
select *
from information_schema.routines
where routine_type = 'PROCEDURE'
This is not a simple thing to do reliably in SQL Server 2005. You might want to look at commercial products such as ApexSQL Clean or SQL Dependency Tracker.
In SQL Server 2008 you could try using the sys.sql_expression_dependencies dynamic management view. For example,
select
quotename(s.name) + N'.' + quotename(o.name) as ProcedureName,
ed.referenced_server_name,
ed.referenced_database_name,
ed.referenced_schema_name,
ed.referenced_entity_name
from sys.sql_expression_dependencies ed
inner join sys.objects o on o.object_id = ed.referencing_id
inner join sys.schemas s on s.schema_id = o.schema_id
where
o.type = 'P'
Hope this helps,
Rhys

Select all non-special principals using SQL Server 2008

I need to make a list of all non-special user accounts retrieved from an SQL Server 2008 database. I can run this query:
SELECT * FROM sys.server_principals WHERE is_disabled <> 1 AND type = 'S';
But the result still includes principals such as sa.
Any idea how to do it?
Nevermind, I think I got it:
SELECT * FROM sys.server_principals WHERE
is_disabled <> 1 AND
type = 'S' AND
IS_SRVROLEMEMBER('sysadmin', [name]) = 0

SQL Server trigger - connection info

is it possible to get MSSQL connection info?not onli SUSER_ID(), SUSER_NAME(), ORIGINAL_LOGIN(), BUT other like:
IP
Connection string
ect..
You can get some more information from sys.dm_exec_connections:
e.g.
SELECT *
FROM sys.dm_exec_connections
WHERE session_id = ##SPID
This will get the connection info available for the current process (SPID).
This doesn't give the full connection string, but does give some more info like IP address (client_net_address).
This will work for SQL Server 2005 and above.
You didn't mention the version of SQL Server that you're using, but this should work for SQL 2005 and above. You can change the ##SPID as needed.
SELECT
conn.session_ID as SPID,
conn.client_net_address as IPAddress,
sess.host_name as MachineName,
sess.program_name as ApplicationName,
login_name as LoginName
FROM
sys.dm_exec_connections conn
INNER JOIN sys.dm_exec_sessions sess ON
conn.session_ID = sess.session_ID
WHERE
conn.session_ID = ##SPID