Getting ORA-01036 error when using output parameter in C# - c#

I am having a problem with an Output parameter in C#/Oracle. I have isolated the code that I need to get working.
This is part of a much larger SQL statement, so do not worry too much if it doesn't make sense. In short I need to copy a row, give it a new ID and return that new ID. I tried using "RETURNING" which did not work. I see no reason why the code below should not work, but I'm getting an "ORA-01036: illegal variable name/number" error. Can anyone see what I'm doing wrong?
using (OracleConnection conn = new OracleConnection(connString))
{
// Open connection and create command.
conn.Open();
using (OracleCommand cmd = new OracleCommand())
{
cmd.Connection = conn;
cmd.CommandType = CommandType.Text;
cmd.Parameters.Add("outValue", OracleType.Int32).Direction = ParameterDirection.Output;
cmd.CommandText = "SELECT seq.nextval INTO :outValue FROM dual";
try
{
cmd.ExecuteNonQuery();
}
catch (Exception e)
{
// This is just to see the exception when it fails.
}
}
}

The name of the parameter doesn't match.
cmd.Parameters.Add(":outValue", OracleType.Int32).Direction.......;
^
I have also seen this variation on the query syntax
"BEGIN SELECT seq.nextval INTO :outValue FROM dual END;"

You are using named parameters. Try setting:
cmd.BindByName = true;

Have you tried 'returning' keyword like this?
This code works for me.
using (OracleConnection conn = new OracleConnection(connString))
{
// Open connection and create command.
conn.Open();
using (OracleCommand cmd = new OracleCommand())
{
cmd.Connection = conn;
cmd.CommandType = CommandType.Text;
cmd.Parameters.Add("outValue", OracleType.Int32).Direction = ParameterDirection.Output;
cmd.CommandText = "insert into table (id, value) values (seq.nextval, 'value') returning id into :outValue";
cmd.ExecuteNonQuery();
}
}

Related

c# cmd.ExecuteReader() Hang up

I'm new in c# and want to call store procedure in the sql server database ,for that purpose write this code:
using (SqlConnection con = new SqlConnection("Data Source=ipaddress;Initial Catalog=database;User ID=userid;Password=password;"))
{
using (SqlCommand cmd = new SqlCommand("exec web.sp_getTotalBillPayam "+Convert.ToInt64(phoneNumber) +",'"+password.Trim()+"',72107603,1067", con))
{
con.Open();
SqlDataReader reader = cmd.ExecuteReader();
...
when run that code every thing is ok but store procedure not return to me any result ,goto debug i realized in this line run:
SqlDataReader reader = cmd.ExecuteReader();
but debugger not go to the next line of code and wait that line run finish,after 5 min that line not finish and dont go next line of code,what happen?How can i solve that problem?thanks.
Your command is not attached to your connection-- and your use of parameters is dangerous. Try this instead:
EDIT: Sorry, your command is attached to the connection, didn't see that being passed in. Either way, this is the correct pattern for calling a stored proc
using (SqlConnection con = new SqlConnection("Data Source=ipaddress;Initial Catalog=database;User ID=userid;Password=password;")) {
con.Open();
using (SqlCommand cmd = con.CreateCommand()) {
cmd.CommandText = "web.sp_getTotalBillPayam";
cmd.CommandType = System.Data.CommandType.StoredProcedure;
//repeat this for each parameter
var parameter = cmd.CreateParameter();
parameter.ParameterName = "PhoneNumber"; //this must match whatever your parameters are to your stored proc
parameter.DbType = System.Data.DbType.Int64;
parameter.Direction = System.Data.ParameterDirection.Input;
parameter.Value = phoneNumber;
cmd.Parameters.Add(parameter);
...
//if you have an OUTPUT result from your proc, add a a parameter called RETURNS with a direction of ParameterDirection.Return and check value AFTER executing
using (SqlDataReader reader = cmd.ExecuteReader()) {
//if your results are a SELECT query they will be here
}
}
}

C# MySql Parameterized Query makes longs into null

The code is based on https://dev.mysql.com/doc/connector-net/en/connector-net-programming-prepared-preparing.html
public void TableTest(string connectionString)
{
string sqlToCreateTable = #"CREATE TABLE IF NOT EXISTS my_table
(auction_key BIGINT NOT NULL, auction_owner VARCHAR(25), first_seen BIGINT,
PRIMARY KEY(auction_key))";
string sqlInsertOrUpdateAuction = "INSERT INTO my_table (auction_key) VALUES (#my_auc_id); ";
using (MySqlConnection dbConnection = new MySqlConnection(connectionString))
{
dbConnection.Open();
// is the table in the database?
MySqlCommand cmd = new MySqlCommand(sqlToCreateTable, dbConnection);
cmd.ExecuteNonQuery();
cmd.Parameters.AddWithValue("#my_auc_id", 123456);
cmd = new MySqlCommand(sqlInsertOrUpdateAuction, dbConnection);
cmd.ExecuteNonQuery();
}
}
The error is that 123456 is seen as null.
Message=Column 'auction_key' cannot be null
I tried changing the "strict" setting in my.ini and it makes no difference.
Help please.
Well, you add the parameter to the command and then instantiate a new command:
cmd.Parameters.AddWithValue("#my_auc_id", 123456);
cmd = new MySqlCommand(sqlInsertOrUpdateAuction, dbConnection);
If you do that, the command will no longer have the value for the #my_auc_id. Try switching those two lines:
cmd = new MySqlCommand(sqlInsertOrUpdateAuction, dbConnection);
cmd.Parameters.AddWithValue("#my_auc_id", 123456);
Hope this helps.
You could alleviate your issue, by simply doing the following:
using(var connection = new MySqlConnection(dbConnection))
{
connection.Open();
using(var command = new MySqlCommand(createTableQuery, connection))
{
command.ExecuteNonQuery();
}
using(var command = new MySqlCommand(insertOrUpdate, connection))
{
command.Parameters.Add("..", SqlDbType = SqlDbType.Int).Value = 123456;
command.ExecuteNonQuery();
}
}
Keep in mind that ExecuteNonQuery will return a zero or one, if it successfully worked. Also you may want to manually specify the SqlDbType. To avoid SQL inferring incorrectly. Also, this will correctly scope your MySqlCommand, so you can correctly utilize for the queries.
And according to the documentation, it does implement the IDisposable to utilize the using block. This ensures you instantiate your MySqlCommand again.

C# SQL, Multiple Commands

I'm trying to write a method which should communicate with database, but I'm not sure if my approach is right.
public void dbWorkerLogin(int workerNumber) {
// Connection string stored in "conn"
if (!new SqlCommand("Some Command WHERE id=" +workernumber,conn).executeReader().HasRows)
{
new SqlCommand("exec STORED_PROCEDURE1 " + workerNumber, conn).ExecuteNonQuery();
new SqlCommand("exec STORED_PROCEDURE2 " + workerNumber, conn).ExecuteNonQuery();
}
else
{
new SqlCommand("exec STORED_PROCEDURE3 " + workerNumber,conn).ExecuteNonQuerry();
}
1) Is it ok to write it like this and start each SqlCommand with keyword new? Or should I do something like:
SqlCommand command = new SqlCommand(null, conn);
command = ...;
and then recycle the variable 'command' or this way?
using(SqlCommand cmd = new SqlCommand("COMMAND", conn);
2) Will my procedures work or should I use SqlCommand.Prepare() function that will covert my data into correct datatypes? eg. workerNumber is int, but in database it is stored as decimal.
using (SqlCommand cmd = new SqlCommand("STORED_PROCEDURE", conn))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parametres.Add("#id", SqlDbType.Decimal).Value = workNumber;
cmd.Prepare();
cmd.ExecuteNonQuery();
}
Can you please somehow sum up what to use, what better not to? Unfortunately I can't test that first code because of limited access to DB so I'm not sure if it can be executed without errors or not.
Thank you for any help on this subject!
EDIT:
After a few hours I reach to this stage:
public int getWorkerNumber(string uniqueID)
{
using (conn = new SqlConnection(ConfigurationManager.ConnectionStrings["dbConnect"].ConnectionString))
{
conn.Open();
using (SqlCommand cmd = new SqlCommand("SELECT number FROM worker WHERE workerID = #id",conn))
{
cmd.Parameters.Add("#id", SqlDbType.Decimal).Value = uniqueID;
using (SqlDataReader reader = cmd.ExecuteReader())
{
int answer;
while (reader.Read())
{
answer = (int)reader.GetDecimal(0);
}
return answer;
}
}
}
}
And this one:
public string dbLoginWorker(int workerNumber)
{
SqlCommand cmd;
SqlDataReader reader;
using (conn = new SqlConnection(ConfigurationManager.ConnectionStrings["dbConnect"].ConnectionString))
{
conn.Open();
cmd = new SqlCommand("SELECT column FROM table WHERE id= #workernumber", conn);
cmd.Parameters.Add("#workernumber", SqlDbType.Decimal).Value = workerNumber;
reader = cmd.ExecuteReader();
if (!reader.HasRows)
{
cmd = new SqlCommand("STORED_PROCEDURE1", conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#ID", SqlDbType.Decimal).Value = workerNumber;
cmd.Parameters.Add("#VARCHAR", SqlDbType.VarChar).Value = "text";
cmd.Prepare();
reader.Close();
cmd.ExecuteNonQuery();
cmd.Dispose();
reader.Dispose();
return "procedure 1 executed";
else
{
cmd = new SqlCommand("STORED_PROCEDURE2", conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#ID", SqlDbType.Decimal).Value = workerNumber;
cmd.Parameters.Add("#INT", SqlDbType.SmallInt).Value = 1;
cmd.Parameters.Add("#VARCHAR", SqlDbType.VarChar).Value = "text";
cmd.Prepare();
reader.Close();
cmd.ExecuteNonQuery();
cmd.Dispose();
reader.Dispose();
return "procedure 2 executed";
}
}
}
Both methods are functional (if I did no mistake in rewriting :) ). I'm not sure which of these methods (1st or 2nd) are better in terms of stability and if this approach is better and more ressistant to SQL Injection. Can someone comment on this subject? Thank you again for any help!
1) It is best to always use USING blocks when possible. This includes SqlConnection, SqlCommand, SqlReader and other objects that implement IDisposable. USING blocks automatically close and dispose of the objects, so you do not have to do so.
2) I believe that you are using the Prepare() method in the wrong place. Look at the following StackOverflow article for proper usage:
PrepareMethodInstructions.
3) in the dbLoginWorker() method, the first query is just used to determine if rows are found. Therefore, I suggest changing the SELECT command to SELECT TOP 1 column FROM table WHERE id= #workernumber so that the query is faster and more efficient.
4) I do not believe your commands are subject to SQL Injection attacks because they are fully parameterized. Good job on that one.
5) As a general thought, I suggest reading up on refactoring techniques. Your dbLoginWorker() method could be made more readable and maintainable, as well as self-documenting, if you created three additional methods, one for each SQL command, and named them something appropriate. You could also setup a method for creating a connection based on a connection name, and you would not have as much duplicate code. For example:
public static SqlConnection GetConnection(string connectionName)
{
SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings[connectionName].ConnectionString);
conn.Open();
return conn;
}
public string dbLoginWorker(int workerNumber)
{
using (conn = GetConnection("dbConnect"))
{
if (CanFindWorkerNumber(conn, workerNumber))
ExecuteProcedure1(conn);
else
ExecuteProcedure2(conn);
}
}
public bool CanFindWorkerNumber (SqlConnection conn, int workerNumber)
{
bool success = false;
using (SqlCommand cmd = new SqlCommand("SELECT TOP 1 column FROM table WHERE id= #workernumber", conn))
{
cmd.Parameters.Add("#workernumber", SqlDbType.Decimal);
cmd.Prepare();
cmd.Parameters[0].Value = workerNumber;
success = cmd.ExecuteScalar() != null;
}
return success;
}
public void ExecuteProcedure1(SqlConnection conn)
{
using (SqlCommand cmd = new SqlCommand("STORED_PROCEDURE1", conn))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#ID", SqlDbType.Decimal);
cmd.Parameters.Add("#VARCHAR", SqlDbType.VarChar);
cmd.Prepare();
cmd.Parameters[0].Value = workerNumber;
cmd.Parameters[1].Value = "text";
cmd.ExecuteNonQuery();
}
}
public void ExecuteProcedure1(SqlConnection conn)
{
using (SqlCommand cmd = new SqlCommand("STORED_PROCEDURE1", conn))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#ID", SqlDbType.Decimal);
cmd.Parameters.Add("#INT", SqlDbType.SmallInt).Value);
cmd.Parameters.Add("#VARCHAR", SqlDbType.VarChar);
cmd.Prepare();
cmd.Parameters[0] = workerNumber;
cmd.Parameters[1] = 1;
cmd.Parameters[2] = "text";
cmd.ExecuteNonQuery();
}
}
You could actually do this in one SQL commend. Right now you are pulling back a result set only to see if it has rows or not, then executing different commands based on that. You should be able to do that in one command, disposing of it and the connection appropriately:
var sql =
#"
IF EXISTS(Some Command WHERE id=#workernumber)
BEGIN
exec STORED_PROCEDURE1 #workernumber;
exec STORED_PROCEDURE2 #workernumber;
END
ELSE
exec STORED_PROCEDURE3 #workernumber;
";
Note that you're not vulnerable to SQL injection because you're not dealing with strings, only integers.

Getting an error when calling stored procedure from C#

I am getting following error when calling a stored procedure in SQL Server from C#:
Line 1: Incorrect syntax near 'spGet_Data'.
Here is my code:
public string GetData (string destinationFile)
{
string conectionString = "uid=One_User;pwd=One_Password;database=One_Database;server=One_Server";
SqlConnection con = new SqlConnection(conectionString);
SqlCommand sqlCmd = new SqlCommand();
string returnValue = string.Empty;
string procedureName = "spGet_Data";
sqlCmd.CommandType = CommandType.StoredProcedure;
sqlCmd = new SqlCommand(procedureName, con);
sqlCmd.Parameters.AddWithValue("#FileName", destinationFile);
con.Open();
var returnParameter = sqlCmd.Parameters.Add("#ret", SqlDbType.VarChar);
returnParameter.Direction = ParameterDirection.ReturnValue;
sqlCmd.ExecuteNonQuery();
returnValue = returnParameter.Value.ToString();
con.Close();
return returnValue;
}
Procedure itself returning data properly, I checked connection it is in Open state.
What else it can be?
Thank you.
The problem lies in the fact that you create the command two times.
After the first initialization you set correctly the CommandType to StoredProcedure, but once again you created the command and this time you forgot to set the CommandType
Just remove the first initialization, leave only the second one and move the CommandType setting after the initialization
SqlConnection con = new SqlConnection(conectionString);
string returnValue = string.Empty;
string procedureName = "spGet_Data";
SqlCommand sqlCmd = new SqlCommand(procedureName, con);
sqlCmd.CommandType = CommandType.StoredProcedure;
You create a SqlCommand object, then set it's CommandType property, then overwrite it by calling new on your command object again. Written out correctly, your code should look like this:
public string GetData (string destinationFile)
{
string conectionString = "uid=One_User;pwd=One_Password;database=One_Database;server=One_Server";
SqlConnection con = new SqlConnection(connectionString);
SqlCommand sqlCmd = new SqlCommand(procedureName, con);
sqlCmd.CommandType = CommandType.StoredProcedure;
string returnValue = string.Empty;
string procedureName = "spGet_Data";
sqlCmd.Parameters.AddWithValue("#FileName", destinationFile);
con.Open();
var returnParameter = sqlCmd.Parameters.Add("#ret", SqlDbType.VarChar);
returnParameter.Direction = ParameterDirection.ReturnValue;
sqlCmd.ExecuteNonQuery();
returnValue = returnParameter.Value.ToString();
con.Close();
return returnValue;
}
Also, I would highly suggest that you surround your SqlConnection and SqlCommand objects with the Using Statement. Much like this:
public string GetData (string destinationFile)
{
using (SqlConnection con = new SqlConnection(connectionString))
{
using (SqlCommand sqlCmd = new SqlCommand(procedureName, con))
{
}
}
}
The benefit of doing it this way is cleaner code and since your command and connection objects implement IDisposable, they will be handled by GC once they fall out of scope.
By the way, you have 'conectionString' misspelled; I fixed it in my code examples.
Whoops. This is being done, albeit incorrectly. See the other answer.
See SqlCommand.CommandType. You need to tell it to be treated as an sproc call. E.g.
sqlCmd.CommandType = CommandType.StoredProcedure;
Otherwise it results in an invalid SQL statement (i.e. running spGet_Data verbatim in an SSMS query should produce a similar messages).

Problems with Executing a DB2 External Stored Procedure

I am trying to call an external stored procedure (calls an RPG program). I keep getting the following error:
"Exception Details: IBM.Data.DB2.iSeries.iDB2SQLErrorException: SQL0104 Token #SSN was not valid. Valid tokens: :."
Here is my code:
using (iDB2Connection conn = new iDB2Connection(_CONNSTRING))
{
conn.Open();
string sqlStatement = "MPRLIB.SIGNTIMESHEET (#SSN, #SIGNATURE, #WORKSTATION, #TOTALHOURS, #COMMENT)";
//string sqlStatement = "MPRLIB.SIGNTIMESHEET (?, ?, ?, ?, ?)";
iDB2Command cmd = conn.CreateCommand();
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = sqlStatement;
cmd.Parameters.Add("#SSN", timesheet.EmployeeUniqueKey.ToString("0000000000"));
cmd.Parameters.Add("#SIGNATURE", timesheet.EmployeeTypedName);
cmd.Parameters.Add("#WORKSTATION", timesheet.EmployeeSignedComputer);
cmd.Parameters.Add("#TOTALHOURS", GetJobHoursTotal(timesheet.Id).ToString("00000.000").Replace(".", ""));
cmd.Parameters.Add("#COMMENT", timesheet.EmployeeComments);
cmd.ExecuteNonQuery();
conn.Close();
}
I can't seem to figure out what is happening or why I am getting the above error. My connection string looks like:
private const string _CONNSTRING = "DataSource=192.168.50.200;DefaultCollection=QMFILES;Naming=sql;UserID=XXX;Password=XXX;";
Could it be a library list issue? The program just references one file that is in the library list. Any suggestions?
Try like this:
using (var conn = new iDB2Connection(_CONNSTRING))
using (var cmd = conn.CreateCommand())
{
conn.Open();
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "MPRLIB.SIGNTIMESHEET";
cmd.Parameters.Add("#SSN", timesheet.EmployeeUniqueKey.ToString("0000000000"));
cmd.Parameters.Add("#SIGNATURE", timesheet.EmployeeTypedName);
cmd.Parameters.Add("#WORKSTATION", timesheet.EmployeeSignedComputer);
cmd.Parameters.Add("#TOTALHOURS", GetJobHoursTotal(timesheet.Id).ToString("00000.000").Replace(".", ""));
cmd.Parameters.Add("#COMMENT", timesheet.EmployeeComments);
cmd.ExecuteNonQuery();
}

Categories