SqlDependency causes error in other application - sql-server

I have a project where I need to monitor changes in a 3rd party database.
SqlDependency seem like a good solution but it causes the following error in the 3rd party application.
INSERT failed because the following SET options have incorrect
settings: 'ANSI_NULLS, QUOTED_IDENTIFIER, ANSI_PADDING'. Verify that
SET options are correct for use with indexed views and/or indexes on
computed columns and/or filtered indexes and/or query notifications
and/or XML data type methods and/or spatial index operations.
(The application works fine when my test program below is not running)
What SET options does this refer to?
The only set operation I have done is ALTER DATABASE TestDb SET ENABLE_BROKER to enable notifications.
I also did:
CREATE QUEUE ContactChangeMessages;
CREATE SERVICE ContactChangeNotifications
ON QUEUE ContactChangeMessages
([http://schemas.microsoft.com/SQL/Notifications/PostQueryNotification]);
Here is my Linqpad test code which works fine if I insert/update/delete records in management studio.
void Main() {
const string cs = "Data Source=.;Initial Catalog=TestDb;Trusted_Connection=True";
var are = new AutoResetEvent(false);
using (var connection = new SqlConnection(cs)) {
connection.Open();
SqlDependency.Start(cs);
using (var cmd = new SqlCommand()) {
cmd.Connection = connection;
cmd.CommandType = CommandType.Text;
cmd.CommandText = "SELECT orderNo FROM dbo.Orders WHERE ProductNo = '111'";
var dep = new SqlDependency(cmd, null, 60);
dep.OnChange += (s,e) => {
Console.WriteLine(e.Info);
are.Set();
};
using (var reader = cmd.ExecuteReader()) {
while (reader.Read()) {
}
}
are.WaitOne();
SqlDependency.Stop(cs);
}
}
}
I do not know, and can not change, how the 3rd part app connects to the database. I can run the sql profiler if more information is required.

It refers exactly to the SET options mentioned in the error message:
SET options have incorrect settings: 'ANSI_NULLS, QUOTED_IDENTIFIER,
ANSI_PADDING'.
The correct settings, along with other restrictions, are described in Creating a Query for Notification:
When a SELECT statement is executed under a notification request, the
connection that submits the request must have the options for the
connection set as follows:
ANSI_NULLS ON
ANSI_PADDING ON
ANSI_WARNINGS ON
CONCAT_NULL_YIELDS_NULL ON
QUOTED_IDENTIFIER ON
NUMERIC_ROUNDABORT OFF
ARITHABORT ON
Note Note
Setting ANSI_WARNINGS to ON implicitly sets ARITHABORT to ON when the
database compatibility level is set to 90. If the database
compatibility level is set to 80 or earlier, the ARITHABORT option
must explicitly be set to ON.
These settings are affected by:
the current database settings, which can be viewed in sys.databases
the session settings, which can be viewed in sys.dm_exec_sessions
by procedure/trigger create settings, which can be viewed using OBJECTPROPERTY().
You need to find which property from the ones mentioned in the error message is non-conforming and why (probably is a database setting). Most likely is a 80 compatibility level set on the database.
Update. Nevermind that, you say that you can successfully create a query notification but then the application itself fails. The application must be explicitly setting one of these settings OFF on it's connection (you can validate by inspecting sys.dm_exec_sessions). You must contact the application vendor, seems like she is very explicitly (albeit probably unintentionally) making his application incompatible with query notifications.

Related

SQL Server : get messages from referenced entities procedure in code

I'm running big dependency scan on legacy db and see that some objects have obsolete ref links, if you run this code in SSMS for View that points to not existing table like in my case, you will get your output on Results tab AND error info in Messages . Like in my case below.
I tried to check all env things I know and output of this stored procedure, but didn't see any indication.
How I can capture this event as I'm running this in looped dynamic SQL script and capture output in my table for further processing?
Updated:
it just text in Message box ,on error, you still have output on
Results tab
this is sp, it loop thru object list I took from sys.object and run this string as my sample to get all dependencies, load all into table. This call to
sql_reference_entities is the only way to get inter database
dependency on column level. So I need stick to this 100$>
--
Select *
From sys.dm_sql_referenced_entities('dbo.v_View_Obs_Table','Object')
--
----update------
This behavior was fixed in SQL Server 2014 SP3 and SQL Server 2016 SP2:
Starting from Microsoft SQL Server 2012, errors raised by
sys.dm_sql_referenced_entities (such as when an object has undergone a
schema change) cannot be caught in a TRY...CATCH Transact-SQL block.
While this behavior is expected in SQL Server 2012 and above, this
improvement introduces a new column that's called is_incomplete to the
Dynamic Management View (DMV).
KB4038418 - Update adds a new column to DMV sys.dm_sql_referenced_entities in SQL Server 2014 and 2016
----update-------
The tldr is that you can't capture these on the server side, and must use a client program in C#, PowerShell or some other client that can process info messages.
That DMV is doing something strange that I don't fully understand. It's generating errors (which a normal UDF is not allowed to do), and those errors do not trigger a TRY/CATCH block or set ##error. EG
create table tempdb.dbo.foo(id int)
go
create view dbo.v_View_Obs_Table
as
select * from tempdb.dbo.foo
go
drop table tempdb.dbo.foo
go
begin try
Select * From sys.dm_sql_referenced_entities('dbo.v_View_Obs_Table','Object')
end try
begin catch
select ERROR_MESSAGE(); --<-- not hit
end catch
However these are real errors, as you can see running this from client code:
using System;
using System.Data.SqlClient;
namespace ConsoleApp6
{
class Program
{
static void Main(string[] args)
{
using (var con = new SqlConnection("Server=.;database=AdventureWorks;integrated security=true"))
{
con.Open();
con.FireInfoMessageEventOnUserErrors = true;
con.InfoMessage += (s, a) =>
{
Console.WriteLine($"{a.Message}");
foreach (SqlError e in a.Errors)
{
Console.WriteLine($"{e.Message} Number:{e.Number} Class:{e.Class} State:{e.State} at {e.Procedure}:{e.LineNumber}");
}
};
var cmd = con.CreateCommand();
cmd.CommandText = "Select * From sys.dm_sql_referenced_entities('dbo.v_View_Obs_Table','Object')";
using (var rdr = cmd.ExecuteReader())
{
while (rdr.Read() || (rdr.NextResult() && rdr.Read()))
{
Console.WriteLine(rdr[0]);
}
}
Console.ReadKey();
}
}
}
}
outputs
Invalid object name 'tempdb.dbo.foo'.
Invalid object name 'tempdb.dbo.foo'. Number:208 Class:16 State:3 at v_View_Obs_Table:4
0
The dependencies reported for entity "dbo.v_View_Obs_Table" might not include references to all columns. This is either because the entity references an object that does not exist or because of an error in one or more statements in the entity. Before rerunning the query, ensure that there are no errors in the entity and that all objects referenced by the entity exist.
The dependencies reported for entity "dbo.v_View_Obs_Table" might not include references to all columns. This is either because the entity references an object that does not exist or because of an error in one or more statements in the entity. Before rerunning the query, ensure that there are no errors in the entity and that all objects referenced by the entity exist. Number:2020 Class:16 State:1 at :1

How to disable in Excel automatic refresh connection calling SQL stored procedure?

Whenever I change windows of opened workbooks and come back to MyFile.xlsb where I have defined external connection, the refresh of all pivot tables in MyFile.xlsb runs automatically. Needless to add it is very annoying feature. How to disable it? How to run refresh all only on demand. Important note. This problem occurs only on computers of the users I distribute MyFile.xlsb. On my computer it works ok.
I have defined the external connection as a reference to stored procedure in SQL.
Connection string:
Provider=SQLOLEDB.1;
Integrated Security=SSPI;
Persist Security Info=True;
Initial Catalog=MyDataBase;
Data Source=MyServerName;
Use Procedure for Prepare=1;
Auto Translate=True;
Packet Size=4096;
Workstation ID=MyWorkstationID;
Use Encryption for Data=False;
Tag with column collation when possible=False
Here is SQL stored procedure I call.
CREATE PROCEDURE [dbo].[MyProcedure]
AS
BEGIN
-- part one, show user what he has to see
SELECT *
FROM [dbo].[MyView]
ORDER BY 1
-- part two, get user data
INSERT INTO dbo.My_other_table_logins_history
SELECT
GETDATE(),
ORIGINAL_LOGIN()
END
The concept of using this procedure is explained here:
SQL procedure from Excel run from connection properties with user login as parameter
Try running this:
Option Explicit
Public Sub disableAutoRefreshConnection()
Dim cnn As WorkbookConnection
For Each cnn In ActiveWorkbook.Connections
With cnn.OLEDBConnection
.BackgroundQuery = False
If .Refreshing Then .CancelRefresh
.EnableRefresh = False
.RefreshOnFileOpen = False
.RefreshPeriod = 0
End With
Next
End Sub
BackgroundQuery Default: True; If queries are asynchronous
CancelRefresh Cancels refresh operations in progress
EnableRefresh Default: True; If connection can be refreshed by the user
RefreshOnFileOpen Default: False; If it auto-updates each time workbook is opened
RefreshPeriod Default: 0; Number of minutes between refreshes

Error while updating Database with mssql_query

I'm using mssql_query to connect to an existing SQL Server 2008 Database.
SELECT querys are ok, but when I run UPDATE querys like the following:
mssql_query("UPDATE TABLENAME SET fieldname = 1 WHERE Pk = '".$pk."'");
I get this error:
UPDATE failed because the following SET options have incorrect
settings: 'ANSI_NULLS, QUOTED_IDENTIFIER, CONCAT_NULL_YIELDS_NULL,
ANSI_WARNINGS, ANSI_PADDING'. Verify that SET options are correct for
use with indexed views and/or indexes on computed columns and/or
filtered indexes and/or query notifications and/or XML data type
methods and/or spatial index operations. (severity 16)
Here is my connection code to Database:
$server = 'SRVSQL';
// Connect to MSSQL
$link = mssql_connect($server, 'xx', 'xxxxxx');
if (!$link) {
die('Something went wrong while connecting to MSSQL');
}
$conn = mssql_select_db('xxxxxxx',$link);
You might have to explicitly change the settings by turning the settings on. You can do so by issuing the following query prior to the UPDATE statement:
SET
ANSI_NULLS,
QUOTED_IDENTIFIER,
CONCAT_NULL_YIELDS_NULL,
ANSI_WARNINGS,
ANSI_PADDING
ON;
Should there be additional settings yielding errors, those might have to be changed as well.
See also: ANSWER: UPDATE failed because the following SET options have incorrect settings: 'ANSI_NULLS, QUOTED_IDENTIFIER'

SQL Server transactions - whole db locked?

I have a problem on specific SQL Server 2008 customer installation. I wrote the code below to simulate the problem which happens in more complex system. There are two connections (each one with own transaction) opened and each connection modifies a table. Modified tables do not relate to each other. On development platform and other existing customer installations the code works fine. Only at one specific customer we have a problem that the second update in nested transaction hangs. I could make a workaround by moving the first update after commit of nested transaction.
I assume in that specific installation the db is configured to lock down the whole db when a transaction is started. But using DBCC useroptions results in very similar output on systems where the code works and this one.
How can I identify what's wrong here ?
Here's DBCC useroptions output from the problematic DB (SQL Server 2008) and my simplified test code:
textsize 2147483647
language Deutsch
dateformat dmy
datefirst 1
lock_timeout -1
quoted_identifier SET
arithabort SET
ansi_null_dflt_on SET
ansi_warnings SET
ansi_padding SET
ansi_nulls SET
concat_null_yields_null SET
isolation level read committed
DbCommand command1 =null, command2 = null;
try
{
const string cs = "Provider=SQLOLEDB.1;...";
// open command and a transaction with default isolation level
command1 = DbAccessFactory.CreateInitialzedCommand("System.Data.OleDb", cs, true);
// select something
command1.CommandText = "select * from plannerOrderHeaders where ...";
DataSet ds = BusinessCasesHelper.Fill(command1, null, "plannerOrderHeaders");
// make some changes in the table
...
// update the table in DB
BusinessCasesHelper.Update(command1, ds, true);
// open command and a transaction with default isolation level on the same CS as command1
command2 = DbAccessFactory.CreateInitialzedCommand("System.Data.OleDb", cs, true);
// select something
command2.CommandText = "select * from mdOmOrders where ...";
ds = BusinessCasesHelper.Fill(command2, null, "mdOmOrders");
// make some changes
...
// update the db
BusinessCasesHelper.Update(command2, ds, true);
command2.Transaction.Commit();
cmd2Commited = true;
command1.Transaction.Commit();
}
catch (Exception e) {...}
And why do you use ""Provider=SQLOLEDB.1" to access MS SQL Server?
And why do you commit instead of closing and disposing?
I can only guess how the mentioned BusinessCasesHelper, DbAccessFactory, etc. are implemented.
But your question implies that your consider your snippet opening transaction inside another transaction in the same context (i.e. on one connection) while I see that they are probably opening two connections which are not being disposed.

Is there an alternative of using a VBScript for enabling FileStream after SQL Server installation?

To use Filestream on a DB 3 steps must be done:
1) enable it a server/instance level
2) enable it (sp_configure) at DB level
3) create a varbinary(max) field that supports filestream
(2) and (3) are done easily with T-SQL
(1) is doable manually from SQL Server Configuration Manager, basically what I need is to check all the 3 checkboxes:
(source: sql-server-performance.com)
but how is it possible to automize it?
I found this artcile "Enabling filestream usin a VBScript", is there another way to do it than using VBScripts? May be something that is possible to do only with 2008R2?
In case it VBScript is the only solution, which are the possible downsides?
The only way other than clicking in the Configuration Manager is via WMI (which is what the VBScript does). If you don't like VB, here's how I've been configuring it from C# (note that the code needs to run with admin privileges (elevated)):
private ManagementObject GetFilestreamManagementObject(string machineName, string instanceName)
{
string managementPath = string.Format(#"\\{0}\root\Microsoft\SqlServer\ComputerManagement10", machineName);
ManagementScope managementScope = new ManagementScope(managementPath);
managementScope.Connect();
SelectQuery query = new SelectQuery("FilestreamSettings", string.Format("InstanceName='{0}'", instanceName));
using (ManagementObjectSearcher searcher = new ManagementObjectSearcher(managementScope, query))
{
ManagementObjectCollection moc = searcher.Get();
if (1 != moc.Count)
{
string exceptionText = String.Format("Expected single instance of FilestreamSettings WMI object, found {0}.", moc.Count);
throw new FilestreamConfigurationException(exceptionText);
}
ManagementObjectCollection.ManagementObjectEnumerator enumerator = moc.GetEnumerator();
if (false == enumerator.MoveNext())
{
throw new FilestreamConfigurationException("Couldn't move ManagementObjectEnumerator to the first entry.");
}
return (ManagementObject)enumerator.Current;
}
}
private void EnableFilestream(int accessLevel)
{
ManagementObject filestreamSettingsObject = GetFilestreamManagementObject("myMachine", "MSSQLSERVER");
ManagementBaseObject methodArgs = filestreamSettingsObject.GetMethodParameters("EnableFilestream");
methodArgs["AccessLevel"] = accessLevel;
methodArgs["ShareName"] = ""; //default
ManagementBaseObject returnObject = filestreamSettingsObject.InvokeMethod("EnableFilestream", methodArgs, null);
if (returnObject == null)
{
throw new FilestreamConfigurationException("Result of calling filestreamSettingsObject.InvokeMethod(\"EnableFilestream\", methodArgs, null)" is null);
}
uint returnValue = (uint)returnObject.GetPropertyValue("ReturnValue");
const uint errorSuccessRestartRequired = 0x80070BC3;
if (returnValue != 0 && returnValue != errorSuccessRestartRequired)
{
Win32Exception win32Exception = new Win32Exception((int)returnValue);
string exceptionText =
string.Format("'EnableFilestream' method returned {0}: {1}", returnValue, win32Exception.Message);
throw new FilestreamConfigurationException(exceptionText);
}
}
Just run this.
USE master
Go
EXEC sp_configure 'show advanced options'
GO
EXEC sp_configure filestream_access_level, 3
GO
EXEC sp_filestream_configure
#enable_level = 3
, #share_name = N'FS';
GO
RECONFIGURE WITH OVERRIDE
GO
More on this
http://www.mssqltips.com/tip.asp?tip=1489
0 = disabled (this is the default)
1 = enabled only for T-SQL access
2 = enabled for T-SQL access and local
file system access
3 = enabled for T-SQL access, local
file system access, and remote file
system access
You can store the script in a stored procedure and call it from your application or anywhere you want.
Here're links on this topic
http://www.mssqltips.com/tip.asp?tip=1838
Link
http://technet.microsoft.com/en-us/library/cc645923.aspx
http://www.sql-server-performance.com/articles/dba/Configure_Filestream_in_SQL_Server_2008_p1.aspx
EDIT
Answer to your comment.
Here's what I call step 2
CREATE DATABASE Archive
ON
PRIMARY ( NAME = Arch1,
FILENAME = 'c:\data\archdat1.mdf'),
FILEGROUP FileStreamGroup1 CONTAINS FILESTREAM( NAME = Arch3,
FILENAME = 'c:\data\filestream1')
LOG ON ( NAME = Archlog1,
FILENAME = 'c:\data\archlog1.ldf')
GO
http://technet.microsoft.com/en-us/library/cc645585.aspx
Check link for all steps
Filestream in Sql Server 2008 Express
Good Luck!
Pawel's solution worked great for us. We were seeing about a 50% failure rate using the VBS -- haven't seen a failure yet with Pawel's approach. Unlike Greg's results, it has worked great for us against a local system. Actually, that's all we have tried it with.
We did have to make a couple of adjustments to Pawel's code. The line
throw new FilestreamConfigurationException("Result of calling filestreamSettingsObject.InvokeMethod(\"EnableFilestream\", methodArgs, null)" is null);
has the final quote character out of place. It should be after the "is null", right before the ");".
We also had to make sure we got the instanceName built correctly. For example, if we had "mymachine\myinstance", we had to make sure that "instanceName=myinstance" and not the full name. Further, if we had "mymachine" (the default instance), we had to have "instanceName=MSSQLSERVER". Maybe that is Greg's problem -- when we had the instanceName set to the wrong thing, we got the same results Greg reports.

Resources