How to retrieve error when launching sqlcmd from C#? - c#

I need to run a stored procedure from a C# application.
I use the following code to do so:
Process sqlcmdCall = new Process();
sqlcmdCall.StartInfo.FileName = "sqlcmd.exe";
sqlcmdCall.StartInfo.Arguments = "-S localhost\\SQLEXPRESS -d some_db -Q \":EXIT(sp_test)\""
sqlcmdCall.Start();
sqlcmdCall.WaitForExit();
From the sqlcmdCall object after the call completes, I currently get an ExitCode of -100 for success and of 1 for failure (i.e. missing parameter, stored proc does not exist, etc...).
How can I customize these return codes?
H.

I have a small VB.Net app that executes system commands like that. To capture error or success conditions I define regular expressions to match the error text output from the command and I capture the output like this:
myprocess.Start()
procReader = myprocess.StandardOutput()
While (Not procReader.EndOfStream)
procLine = procReader.ReadLine()
If (MatchesRegEx(errRegEx, procLine)) Then
writeDebug("Error reg ex: [" + errorRegEx + "] has matched: [" + procLine + "] setting hasError to true.")
Me.hasError = True
End If
writeLog(procLine)
End While
procReader.Close()
myprocess.WaitForExit(CInt(waitTime))
That way I can capture specific errors and also log all the output from the command in case I run across an unexpected error.

If you are trying to call a stored procedure from c# you would want to use ADO.Net instead of the calling sqlcmd via the command line. Look at SqlConnection and SqlCommand in the System.Data.SqlClient namespace.
Once you are calling the stored procedure via SqlCommand you will be able to catch an exception raised by the stored procedure as well we reading the return value of the procedure if you need to.

Even with windows authentication you can still use SqlCommand and SqlConnection to execute, and you don't have to re-invent the wheel for exception handling.
A simple connection configuration and a single SqlCommand can execute it without issue.

Related

Finding sum of values in a column

I am trying to find sum of values in a column using a condition but the result am getting is null am not sure of where the problem is coz i have tried running the sql database access but and it works but when i it at in the progam it does not work
So i need assistance on this one
The code is below
Blockquote
p.Query="SELECT SUM(income) FROM Emp_income WHERE username ='" + frmlogin.username + "'";
using (IDbCommand command = new OleDbCommand(p.Query, p.Con))
{
object answer=command.ExecuteScalar();
lblincome.Text=Convert.ToString(answer);
}
Add try/catch block to ExcuteScalar() for error message, for connection oriented ADO.Net you have to Open connection before executing the command like con.Open()

.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.

incorrect syntax in c# sql command

I've got the following
SqlCommand cmd = getSQLCommand();
using (cmd.Connection)
using (cmd)
{
try
{
string dbName = txt_DatabaseName.Text;
var createDatabaseQuery = "exec ('CREATE DATABASE ' + #databaseName)";
var sqlCommand = new SqlCommand(createDatabaseQuery, cmd.Connection);
sqlCommand.Parameters.Add("#databaseName", SqlDbType.Text);
sqlCommand.Parameters["#databaseName"].Value = dbName.ToString();
cmd.Connection.Open();
sqlCommand.ExecuteNonQuery();
}
catch (SqlException ex)
{
Console.WriteLine(ex.ToString());
ScriptManager.RegisterClientScriptBlock(this, this.GetType(), "alertMessage", "alert('SQL Error. Record not added.')", true);
}
finally
{
cmd.Connection.Close();
}
}
I'm fully aware that params are not supported in DDL operations, so I've got this really cool thread that I've been using to help me write the contents within the "try".
How to use SqlCommand to CREATE DATABASE with parameterized db name?
That said, I'm still getting an exception error for incorrect syntax near 'Database'. This might be a user error but I've been stuck around this for an hour or so now.
Any thoughts/ improvements?
p.s. All I'm trying to do is to create a database programmatically by using a dynamic value of whatever happens to be in txt_DatabaseName.Text (and yes I will try to error handle this in case there's white spaces entered or any chars that are not supported in SQL.
p.p.s Any articles that I can have a look at against sql injection attacks or any suggestions around constructing the method I have to prevent it? This is a simple exercise that I'm doing on my local machine, not public facing but still would like to get ahead of the game if possible.
You don't need the exec part at all. Again you are getting error after removing exec cause you are wrapping your query in single quote 'CREATE DATABASE ' which is getting considered as string literal. It should just be
var createDatabaseQuery = string.Format("CREATE DATABASE {0}",DBnamevariable);
var sqlCommand = new SqlCommand(createDatabaseQuery, cmd.Connection);
Take a look with the sql profiler to see what is being fired against the database. If it is not working try to execute the query in Management studio to see it that is working. It's probably some kind of special character that is not allowed.

get next sequence value Oracle using Ado.Net c#

I have tried various forms of the following method to get the next sequence value from an Oracle DB in my asp.net app. The sql statement works fine in Toad (11g). The sql statement includes "Select ... myschema.mySeq.nextval ... from dual. But the error I receive when I get to cmd.ExecuteNonQuery() -- the error is:
>
Exception Details: Oracle.DataAccess.Client.OracleException: ORA-00942: table or view does not exist
<<
Authentication is a very big deal at the place where I am at. Is this a data Access problem or is something incorrect with my method (below)? If something is incorrect with the code below what is the correction I need to make? Note: the app (big app) has hundreds of calls to SPs (which all work fine), so I basically copied the connection string code and used a constant (like they do throughout the app). If I use an SP this works, but I want to not use an SP just straight forward Ado.Net. What is the fix?
public int getNextPositionSequence(string userSeq)
{
OracleConnection conn = new OracleConnection(DaoHelper.GetConnectionString("AuthenticatedOracleConnectionString"));
conn.Open();
conn.ClientId = userSeq;
string sql = "SELECT ddtms.position_seq.nextval from dual";
OracleCommand cmd = new OracleCommand(sql, conn);
object s = cmd.ExecuteNonQuery(); //<<<--- crashes here
conn.Close();
return 1;
}

Make SQLite connection fail if database is missing? (deleted/moved)

I have the following method inside class DBConnection. I call the method like this: SQLiteConnection conn = DBConnection.OpenDB(); when I want to open an connection, so that I can execute my queries. I can call a similar method when I want to close the connection.
The method:
public static SQLiteConnection OpenDB()
{
try
{
//Gets connectionstring from app.config
string myConnectString =
ConfigurationManager.ConnectionStrings[
"LegMedSQLLite.Properties.Settings.LegMedSQLLiteDBConnectionString"].ConnectionString;
var conn = new SQLiteConnection(myConnectString);
conn.Open();
return conn;
}
catch (SQLiteException e)
{
MessageBox.Show(e.ToString(), "TEST");
return null;
}
}
This all works fine and dandy. The problem is the try-catch though. Let us imagine the following scenario:
The database file has been
moved/delete.
The exception will never be thrown. Actually, the first catch I stumble upon is when I execute my first query - where it figures that there is no such table(s) and it throws its own exception.
I was stunned by this weird phenomenon, but I soon found out that SQLite creates a new
empty database. By empty is mean no tables, nothing, just an SQLite database file with the same name as the old database which was supposed to be there.
This is an issue, I want the application to know if there is something wrong (database not found, corrupted, being used by another process etc.) as soon as I try to call SQLiteConnection conn = DBConnection.OpenDB();.
Naturally, I could try call a File.Exists in my method, but that doesn't seem like a proper solution. Any help?
If you're using System.Data.SQLite, you can add "FailIfMissing=True" to your connection string. SQLiteConnection.Open() will throw a SQLiteException if the database file does not exist.
string ConnectString = "Data Source=file.sdb; FailIfMissing=True";
DbConnection db = new SQLiteConnection(ConnectString);
db.Open(); // Fails if file.sdb does not exist
See SQLite Connection String Samples for another example, look for "Disable create database behaviour".
If you're using Microsoft.Data.Sqlite, you can specify an open mode with Mode=ReadWrite instead of Mode=ReadWriteCreate.
I haven't used SQLite but that is pretty bizarre behaviour to auto create a brand new database.
You could just adjust your try block to do a Select top 1 * From Table immediately after you open the connection, if it works, throw away the result and continue to return your conn object. If it fails, the exception handler should fire.
If you want to detect database corruption issues on start up , you can execute the command
pragma integrity_check;
or
pragma quick_check; ( which is faster, but less thorough )
This returns a single row with the value "ok".
Otherwise it will report errors that it encounters.
For sqlite use this: Suppose you have connection string in textbox txtConnSqlite
Using conn As New System.Data.SQLite.SQLiteConnection(txtConnSqlite.Text)
Dim FirstIndex As Int32 = txtConnSqlite.Text.IndexOf("Data Source=")
If FirstIndex = -1 Then MsgBox("ConnectionString is incorrect", MsgBoxStyle.Exclamation, "Sqlite") : Exit Sub
Dim SecondIndex As Int32 = txtConnSqlite.Text.IndexOf("Version=")
If SecondIndex = -1 Then MsgBox("ConnectionString is incorrect", MsgBoxStyle.Exclamation, "Sqlite") : Exit Sub
Dim FilePath As String = txtConnSqlite.Text.Substring(FirstIndex + 12, SecondIndex - FirstIndex - 13)
If Not IO.File.Exists(FilePath) Then MsgBox("Database file not found", MsgBoxStyle.Exclamation, "Sqlite") : Exit Sub
Try
conn.Open()
Dim cmd As New System.Data.SQLite.SQLiteCommand("SELECT * FROM sqlite_master WHERE type='table';", conn)
Dim reader As System.Data.SQLite.SQLiteDataReader
cmd.ExecuteReader()
MsgBox("Success", MsgBoxStyle.Information, "Sqlite")
Catch ex As Exception
MsgBox("Connection fail", MsgBoxStyle.Exclamation, "Sqlite")
End Try
End Using
I think you can easilly convert it to c# code
This is specific to .NET Core.
Entity Framework Core 5.0 will throw this exception:
System.ArgumentException: Connection string keyword 'failifmissing' is not supported. For a possible alternative, see https://go.microsoft.com/fwlink/?linkid=2142181.
The alternative is to use Mode=ReadWrite in the Connection String.
string connectString = "Data Source=DbFileName.sdb; Mode=ReadWrite;";
ReadWriteCreate - Opens the database for reading and writing, and creates it if it doesn't exist. This is the default.
ReadWrite - Opens the database for reading and writing.
Refer the alternative link provided in the Exception message - https://go.microsoft.com/fwlink/?linkid=2142181
Types of Connection Mode - https://learn.microsoft.com/en-us/dotnet/standard/data/sqlite/connection-strings
Don't catch at that level. Instead, SQLiteConnection should implement IDisposable, meaning you should just return the open connection and allow calling code to handle any exceptions, as well as rely on the Dispose method to close the connection.
If there is no way to change the default SQLite behavior, then you might have to do a File.Exists. That would be better than connecting and creating a new file, checking to see if it's the database you want, then deleting the new file in the catch block.

Categories

Resources