Database.ExecuteNonQuery does not return - c#

I have a very odd issue. When I execute a specific database stored procedure from C# using SqlCommand.ExecuteNonQuery, my stored procedure is never executed.
Furthermore, SQL Profiler does not register the command at all. I do not receive a command timeout, and no exeception is thrown.
The weirdest thing is that this code has worked fine over 1,200,000 times, but for this one particular file I am inserting into the database, it just hangs forever.
When I kill the application, I receive this error in the event log of the database server: "A fatal error occurued while reading the input stream from the network. The session will be terminated (input error: 64, output error: 0). Which makes me think that the database server is receiving the command, though SQL Profiler says otherwise.
I know that the appropiate permissions are set, and that the connection string is right as this piece of code and stored procedure works fine with other files.
Below is the code that calls the stored procedure, it may be important to note that the file I am trying to insert is 33.5MB, but I have added more than 10,000 files larger than 500MB, so I do not think the size is the issue:
using (SqlConnection sqlconn = new SqlConnection(ConfigurationManager.ConnectionStrings["TheDatabase"].ConnectionString))
using (SqlCommand command = sqlconn.CreateCommand())
{
command.CommandText = "Add_File";
command.CommandType = CommandType.StoredProcedure;
command.CommandTimeout = 30 //should timeout in 30 seconds, but doesn't...
command.Parameters.AddWithValue("#ID", ID).SqlDbType = SqlDbType.BigInt;
command.Parameters.AddWithValue("#BinaryData", byteArr).SqlDbType = SqlDbType.VarBinary;
command.Parameters.AddWithValue("#FileName", fileName).SqlDbType = SqlDbType.VarChar;
sqlconn.Open();
command.ExecuteNonQuery();
}
There is no firewall between the server making the call and the database server, and the windows firewalls have been disabled to troubleshoot this issue.

I've seen this once before when uploading XML via a stored proc from one workstation only
We changed the network cable (which routed differently in our big building) and it worked.
Bizarre as this sounds, can you somehow re-mount the server or change cables or bypass a switch etc.

Related

Moving Database from Sybase to SQL Server: ODBC not recognised named parameters

I'm updating an old project, moving its data source from Sybase to SQL Server. The data structures are identical (they're both copies of a commercial database - the Sybase version has been discontinued).
Because it's pretty old, it uses ODBC to connect. The connection strings originally specified a DSN. I've managed to connect to the SQL Server using both a raw connection string and a replacement DSN.
It executes code against the database by pulling command text from a config file and adding named parameters, like so:
var args = new Dictionary<string, object>()
{
{ "#myFirstParam", "myFirstValue" },
{ "#mySecondParam", "mySecondValue" }
}
IDbCommand cmd = Connection.CreateCommand();
cmd.CommandType = CommandType.Text;
cmd.CommandTimeout = Command.Timeout;
cmd.CreateParameters(Command.Parameters, args);
cmd.CommandText = [fetched from config]
IDataReader reader = null;
reader = cmd.ExecuteReader();
This all used to work fine with Sybase.
However, when I run it against SQL, when the reader executes I get the following error:
ERROR [42000] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]Must declare the scalar variable "#myFirstVariable".
I get this error whether I specify the connection as a DSN or a raw string. Stepping through the code, the parameter is certainly declared and has a valid value.
Reading up around this, it appears that this behaviour is to be expected. The Microsoft Documentation on ODBC connection says you can only use named parameters if you're calling a stored procedure, which I am not. Apparently the correct method is to put "?" characters in the command text and ODBC will insert the parameters by index.
If this is correct, I have no idea how this code ever worked with Sybase. I have another project which uses the same code for data loading, specifying named parameters and passing them into SQL command specified in config, but it's pointing at a different SQL Server database.
I presume this may be something to do with the configuration of the database, but I'm pretty lost on what to try from here. Any suggestions would be greatly appreciated.

.NET Dapper/MySql 8.0 issue: Only root user is able to execute stored procedure. Other users get SqlNullValueException [duplicate]

I am trying to setup my .NET 4.7.1 program that is connecting to a MySQL database 8.0 to use the minimum privileges to run.
The .NET program is using MySql.Data to make connection. The minimum right for a user to execute a stored procedure is typically only EXECUTE privilege. This works fine from MySQL workbench or command line.
Upon running the .NET program this does return the following exception:
System.Data.SqlTypes.SqlNullValueException: 'Data is Null. This method or property cannot be called on Null values.'
To make it easy, I have create a very small demo program to demonstrate the issue.
Setup of the database:
CREATE DATABASE Spike;
CREATE PROCEDURE TestAccess()
BEGIN
END;
CREATE USER Spike#localhost IDENTIFIED WITH mysql_native_password BY 'sample';
GRANT EXECUTE ON PROCEDURE `TestAccess` TO Spike#localhost;
Setup program code:
static void Main(string[] args)
{
using (MySqlConnection conn = new MySqlConnection("Server=localhost;Database=Spike;uid=Spike;pwd=sample"))
{
conn.Open();
Console.WriteLine("Connection open");
MySqlCommand cmd = new MySqlCommand();
cmd.Connection = conn;
cmd.CommandText = "TestAccess";
cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.ExecuteNonQuery();
Console.WriteLine("Query executed");
}
Console.ReadKey();
}
The crash happens at the line cmd.ExecuteNonQuery();
The stack from the crash is interesting, since it seems to indicate that the information_schema is queried. When logging all statements I can see that the last statement before the exception is:
SELECT * FROM information_schema.routines WHERE 1=1 AND routine_schema LIKE 'Spike' AND routine_name LIKE 'TestAccess'
I cannot grant different rights on information_schema, but I could give more rights on the stored procedure to make more information visible in the routines table, this feels wrong however. Simple tests with granting CREATE and ALTER access also did not work.
Is there something else I can do, without granting too much privileges?
This appears to be a bug in Connector/NET, similar to bug 75301 but a little different. When it's trying to determine parameter metadata for the procedure, it first creates a MySqlSchemaCollection named Procedures with all metadata about the procedure. (This is the SELECT * FROM information_schema.routines WHERE 1=1 AND routine_schema LIKE 'Spike' AND routine_name LIKE 'TestAccess' query you see in your log.)
The Spike user account doesn't have permission to read the ROUTINE_DEFINITION column, so it is NULL. Connector/NET expects this field to be non-NULL and throws a SqlNullValueException exception trying to read it.
There are two workarounds:
1) The first, which you've discovered, is to set CheckParameters=False in your connection string. This will disable retrieval of stored procedure metadata (avoiding the crash), but may lead to harder-to-debug problems calling other stored procedures if you don't get the order and type of parameters exactly right. (Connector/NET can no longer map them for you using the metadata.)
2) Switch to a different ADO.NET MySQL library that doesn't have this bug: MySqlConnector on NuGet. It's highly compatible with Connector/NET, performs faster, and fixes a lot of known issues.
I found an answer with which I am quite pleased. It is changing the connection string by adding CheckParameters=false:
using (MySqlConnection conn = new MySqlConnection("Server=localhost;Database=Spike;uid=Spike;pwd=sample;CheckParameters=false"))
This disables parameter checking, and thereby information_schema queries.

SQL Slow in code not SSMS

I am running into issues working with a very large table from C# .Net 4.0.
For reference the table has ~120 Million rows.
I can't do even a simple query like
SELECT TOP(50) *
FROM TableName
WHERE CreatedOn < '2015-06-01';
From code it will timeout (Default setting - 15 seconds I believe), but in SSMS it is instant.
There is an index on the column in the WHERE clause. I have also tried explicitly casting the string to a DateTime, and using a DateTime parameter instead of a literal value.
I tried a different query that filters by the PK (bigint, identity, clustered index) If I do something like "Where TableRowID = 1" it works fine from code, but if I try to use "<" or "<=" instead it will timeout (returns instantly in SSMS), regardless of how many rows are turned.
The execution plans are very simple and are exactly the same.
I have tried changing ARITHABORT but that has had no effect.
I tried having the Application connect with my own account (SSPI) instead of its own credentials with no effect.
I have been researching this issue for a few days, but everything I have found blames different execution plans.
Does anyone have any idea what could be causing this issue?
The .Net code looks like this:
private DataSet ExecuteQuery(string query, string db, List<SqlParameter> parms = null)
{
string connectionString = ConfigurationManager.ConnectionStrings[db].ToString();
SqlConnection con = new SqlConnection(connectionString.Trim());
SqlDataAdapter sqlDataAdapter = new SqlDataAdapter();
try
{
con.Open();
DataSet ds = new DataSet();
sqlDataAdapter.SelectCommand = new SqlCommand(query, con);
sqlDataAdapter.SelectCommand.CommandType = CommandType.Text;
if (parms != null)
{
foreach (SqlParameter p in parms)
{
sqlDataAdapter.SelectCommand.Parameters.Add(p);
}
}
sqlDataAdapter.Fill(ds);
if (ds.Tables.Count > 0 && ds.Tables[0].Rows.Count > 0)
{
return ds;
}
return null;
}
finally
{
if (sqlDataAdapter != null)
sqlDataAdapter.Dispose();
if (con != null)
con.Dispose();
}
}
The error message I get in .Net is the standard timeout message:
Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding.
Here are my experience when dealing the issues.
Very C# sql code passed to sql server is
SELECT TOP(50) *
FROM TableName
WHERE CreatedOn < '2015-06-01'
Make sure the criteria. If it takes "instant time" to retrieve records on SSMS, the sql statement and db optimization is ok.
As other people have pointed out, you should post your C# codes and see what happens. There could be other issues. Could that be network? Could that be web.config? Do you call directly from C# code? Do you call via web service?
when you said time out? Does it time out at the time you execute the query. There is very little information you provide. Do you use third party routines (such as written by vendor or your company) to execute queries? If it possible, put the break point at the code that execute sql statement. What I mean is dig all the way to native codes, and put the break codes.
120 million records. Looks like the database has be optimized if it runs very fast on SSMS. I would take look outside SQL server.
good luck
My first step there would be to look at what your code is sending to the sql server. I'd begin by running the sql profiler. if you're not familiar with it. Here is a link on how to use it.
https://www.mssqltips.com/sqlservertip/2040/use-sql-server-profiler-to-trace-database-calls-from-third-party-applications/
After this you may want to look into network traffic times between the 2 servers.
Then look at IIS and see how it's setup. Could be a setting is wrong.
Check the error logs and see if you have any errors as well.
When you execute code in SSMS, the system is setting some default values on your connection. Specifically, look at Tools --> Options --> Query Execution --> Sql Server --> Advanced (and also ANSI). These statements are executed on your behalf when you open a new query window.
When you create your connection object in C#, are you setting these same options? If you don't explicitly set them here, you are taking the default values as defined in the actual SQL Server instance. In SSMS, you can get this by viewing the properties of the server instance and choosing the Connections page. This shows the default connection options.
You can also get this information without using the UI (you can do this in a separate application that uses the same connection string, for example). This article on MSSQLTips should guide you in the right direction.

ExecuteDataSet timeout occurs on very quick stored procedure

I'm try to debug an issue that's cropped up in one of our legacy systems.
This is the code in question
DataSet content = new DataSet();
Database db = DatabaseFactory.CreateDatabase();
DbCommand cmdSearchQuestionLibrary = db.GetStoredProcCommand("CUP_Reports_GetTrainerPerformanceReport");
db.AddInParameter(cmdSearchQuestionLibrary, "#PartnerID", DbType.Int64, partnerId);
db.AddInParameter(cmdSearchQuestionLibrary, "#StartDate", DbType.DateTime, dtStartDate);
db.AddInParameter(cmdSearchQuestionLibrary, "#EndDate", DbType.DateTime, dtEndDate);
db.AddInParameter(cmdSearchQuestionLibrary, "#TrainerId", DbType.Int32, trainerId);
db.AddInParameter(cmdSearchQuestionLibrary, "#AssessmentType", DbType.Int32, assessmentType);
content = db.ExecuteDataSet(cmdSearchQuestionLibrary);
The timeout occurs on the db.ExecuteDataSet. I traced this in SQL Server Profiler and run the same query against the same database and it's taking less than a second to return the data.
If I extend the timeout I can see that it's taking over a minute to return the same data which isn't acceptable.
Is there something going on here that I'm missing? I wondered if db.GetStoredProcCommand is opening a connection that needs to be closed and it's just waiting for that connection to close.
After trying several things it turns out that the solution was to add WITH Recompile onto the Stored Procedure. Seems that the DB was holding onto a bad execution plan.

INSERT INTO command not working

Before I start, I'll let you know that I tried everything that has already been suggested on previous questions and other websites before I considered posting a question myself. As it happens, nothing seems to work and I'm just about fed up with this.
As some background information, this is for my Computing A2 project, so I'm kind of stuck for time now - i.e. I can't be changing loads of my code ideally.
Anyway, onto the issue...
I'm using SQLCe in my code to read from various tables and write to one. So far, the code for reading from the tables works fine, so that's any connection issues out the way first. The piece of code I am struggling with is as follows:
string connectionString = Properties.Settings.Default.BookingSystemDatabaseConnectionString;
using (SqlCeConnection myConnection = new SqlCeConnection(connectionString))
{
myConnection.Open();
try
{
string commandStr = "INSERT INTO bookings(username, room, time) VALUES(#username, #room, #time)";
SqlCeCommand myCommand = new SqlCeCommand(commandStr);
//Passes parameters into SQL command.
myCommand.Parameters.AddWithValue("username", StaticUser.StudentUser.username);
myCommand.Parameters.AddWithValue("room", roomBox.Text);
myCommand.Parameters.AddWithValue("time", timeBox.Text);
//Executes SQL command. Returns the number of affected rows (unecessary for my purposes; a bi-product if you will).
myCommand.ExecuteNonQuery();
}
catch
{
System.Windows.Forms.MessageBox.Show("Could not write new booking to database. This is likely because the database cannot be reached.", "Error");
Program.AccessError = true;
}
myConnection.Close();
}
This is just one of the many ways I have tried to combat the issue I am having. I have also explored:
myCommand.Parameters.Add(new SqlCeParameter("username", StaticUser.StudentUser.username));
to pass the parameters...and another method which escapes me now (using ".Value = StaticUser.StudentUser.username" I think). Furthermore, I have tried using a 'using' statement for the command to save me closing the connection myself (I will probably end up using a solution that uses 'using'). Finally (albeit this isn't a chronological recollection), I tried:
SqlCeCommand myCommand = new SqlCeCommand("INSERT INTO bookings(username, room, time) VALUES(#username, #room, #time)", myConnection)
Again, of course, to no avail.
To highlight the actual symptoms of the issue I am having: The code appears to run fine; stepping through the full method I have pasted above shows that no error is being caught (of course, the message box does not appear - I realised afterwards that stepping through was arguably an unnecessary procedure) and in the other methods I have touched on, the same thing happens. The issue, then, is that the table 'bookings' is not actually being updated.
So, my question, why?
I didn't do the obvious and check the Debug folder for an updated database.
Look for a copy of the database file in your bin/debug folder.
Use full path in connection string, and preferably do not include the sdf file in your project (or at least set build action to None)
i think you are not defining a connection for the command
try
mycommand.connection = connectiostring;

Categories

Resources