Convert Oracle PL/SQL code to C# use ado.net - c#

I use .net 4 and oracle sql and I execution this block code:
DECLARE
Wresult NUMBER;
BEGIN
Wresult :=tis.fuc(1, 3, 5, 44, '3311');
DBMS_OUTPUT.put_line(Wresult);
END;
When I run incorrect input I get "1".
enter image description here
When I run correct input I get "0".
enter image description here
how to show "0" or "1" result into c# use ado.net?
This is my code ado.not:
string str1 = "declare Wresult number;" +
"begin " +
"w:=tis.fuc(:pre1, :pre2, :pre3, :pre4, :pre5);" +
"DBMS_OUTPUT.put_line(Wresult);" +
"end;";
using (OracleConnection connection = new OracleConnection(OracleServer))
{
connection.Open();
using (OracleCommand command = new OracleCommand(str1, connection))
{
command.CommandType = CommandType.Text;
command.Parameters.Add("pre1", OracleDbType.Int32).Value = 1;
command.Parameters.Add("pre2", OracleDbType.Int32).Value = in1;
command.Parameters.Add("pre3", OracleDbType.Int32).Value = in2;
command.Parameters.Add("pre4", OracleDbType.Int32).Value = in3;
command.Parameters.Add("pre5", OracleDbType.Int32).Value = in4;
//command.Parameters.Add("Wresult", OracleDbType.Int32, ParameterDirection.Output);
var result1 = command.ExecuteNonQuery();
//var result1 = command.Parameters["Wresult"].Value;
//vv = Convert.ToInt32(command.Parameters["Wresult"].Value);
}
connection.Close();
}
and I use this to get output but not work .
//command.Parameters.Add("Wresult", OracleDbType.Int32, ParameterDirection.Output);
and finally
var result1 = command.ExecuteNonQuery();
the out put result1 incorrect or correct input is -1 and
when put correct output is work but not show on C# only background on database.

string str1 = "declare Wresult number;" +
"begin " +
"w:=tis.fuc(:pre1, :pre2, :pre3, :pre4, :pre5);" +
"DBMS_OUTPUT.put_line(Wresult);" +
"end;";
An OUT value is still a binded variable, so this should look like:
string str1 = "begin " +
":wout := tis.fuc(:pre1, :pre2, :pre3, :pre4, :pre5);" +
"end;";
at which point you would then have:
command.Parameters.Add("wout", OracleDbType.Int32, ParameterDirection.Output);

Related

C# Update Bool value to Database

I have two radio boxes. One true, the other false. I have a flag set up,
but it didn't work. Here is my code right now
string sqlStatement;
SqlConnection cnn = new SqlConnection(Properties.Settings.Default.cnnString);
cnn.Open();
SqlCommand cmd = cnn.CreateCommand();
cmd.CommandType = CommandType.Text;
sqlStatement = string.Format("UPDATE Results SET Finish = '{0}', Place = '{1}', FinishTime = {2}, Winnings = '{3}' Where ResultsId = '{4}' " + (rdoDidFinish.Checked ? 1 : 0), txtPlace.Text, txtTime.Text, txtWinnings.Text);
cmd.CommandText = sqlStatement;
cmd.ExecuteNonQuery();
cnn.Close();
The error I am getting is:
"Index (zero based) must be greater than or equal to zero and less than the size of the argument list."
I see a few problems here.
NEVER EVER build a SQL Statement by piecing together a string and values, doesn't matter if it is stringbuilder or string.format, or what not. This is language agnostic; DON'T do it in any language. For more information on the dangers, please Google "SQL Injection"
The best thing to do is use paramaterized queries. Sample will follow.
Your problem is actually in your string.Format line. There are 2 errors here
Error 1: I believe the + should be a , here: '{4}' " + (rdoDidFinish.Checked ? 1 : 0)
Error 2 You have 5 placeholders, and only 3 values. 4 if the above (Err 1) statement is corrected
Here is a simple mock up assuming Err 1 fixed.. Need to know what the ResultID value is.
string sqlStatement = "UPDATE Results SET Finish = #Finish, Place = #Place, FinishTime = #FinishTime, Winnings = #Winnings WHERE ResultsId = #ResultID";
using (SqlConnection cnn = new SqlConnection(Properties.Settings.Default.cnnString)) {
SqlCommand cmd = cnn.CreateCommand(sqlStatement, cnn);
cmd.CommandType = CommandType.Text;
cmd.Parameters.AddWithValue("#Finish", (rdoDidFinish.Checked ? 1 : 0)); // I think this belongs here.
cmd.Parameters.AddWithValue("#Place", txtPlace.Text);
cmd.Parameters.AddWithValue("#FinishTime", txtTime.Text);
cmd.Parameters.AddWithValue("#Winnings", txtWinnings.Text);
// cmd.Parameters.AddWithValue("#ResultID", ); ? What belongs here ?
cnn.Open();
cmd.ExecuteNonQuery();
cnn.Close();
}
Please use parameters in a prepared statement!
Example:
var myParam = new SqlParameter();
myParam.ParameterName = "#myParam";
myParam.Value = 1;
comm.Parameters.Add(myParam);
You can use the parameter in your SQL-Statement like
Select * from table where abc = #myparam
Your Where ResultsId = '{4}' does not currently have any values being inserted into it.
Add another parameter after txtWinnings.txt providing the ResultsId and replace the + with a , before (rdoDidFinish.Checked ? 1 : 0) so that it is recognized as its own parameter.
The correct statement should look something like this, where resultId is whatever id you want to search for:
sqlStatement = string.Format("UPDATE Results SET Finish = '{0}', Place = '{1}', FinishTime = {2}, Winnings = '{3}' Where ResultsId = '{4}' ", (rdoDidFinish.Checked ? 1 : 0), txtPlace.Text, txtTime.Text, txtWinnings.Text, resultId);
One final note, in line with the comments on your question, you should always prepare your parameters. So your final result should be something along the lines of:
cmd.CommandText = #"UPDATE Results SET Finish = #finished, Place = #place, FinishTime = #time, Winnings = #winnings Where ResultsId = #resultId ";
cmd.Parameters.Add(new SqlParameter("#finished", System.Data.SqlDbType.Bit).Value = rdoDidFinish.Checked);
cmd.Parameters.Add(new SqlParameter("#place", System.Data.SqlDbType.VarChar).Value = txtPlace.Text);
cmd.Parameters.Add(new SqlParameter("#time", System.Data.SqlDbType.VarChar).Value = txtTime.Text);
cmd.Parameters.Add(new SqlParameter("#winnings", System.Data.SqlDbType.VarChar).Value = txtWinnings.Text);
cmd.Parameters.Add(new SqlParameter("#resultId", System.Data.SqlDbType.Int).Value = resultId);

OracleCommand Update works with interpolated SQL, but not with Parameterized

I'm doing some maintenance on a legacy app uses OracleConnection and OracleCommand to manage our data. I'm Having an issue where a specific update isn't working when I use parameters, but if I convert the same statement to an interpolated string, it's working fine. I'm not getting any exceptions, the update just doesn't happen, and returns a 0 for rows updated. I'm doing other updates with parameters, so I'm curious if anyone sees anything that I might have missed with this one. I've tried with/without the transaction as well as explicitly creating OracleParameter objects to no effect.
The method is below. I've left the parameterized version and the parameter setting commented out for reference.
public int UpdateBusinessEntitlement(int appId, int businessId, int entitlementTypeId, string sso)
{
// Non-Working Parameterized Version
//var sql = "UPDATE APD.APD_BUS_TO_APP_MAP " +
// "SET ENTITLEMENT_TYPE_SEQ_ID = :entitlementTypeId, " +
// "LAST_UPDATE_DATE = SYSDATE, " +
// "LAST_UPDATED_BY = :lastUpdatedBy " +
// "WHERE APP_SEQ_ID = :appId AND BUSINESS_SEQ_ID = :businessId";
var sql = "UPDATE APD.APD_BUS_TO_APP_MAP " +
$"SET ENTITLEMENT_TYPE_SEQ_ID = {entitlementTypeId}, " +
"LAST_UPDATE_DATE = SYSDATE, " +
$"LAST_UPDATED_BY = {sso} " +
$"WHERE APP_SEQ_ID = {appId} AND BUSINESS_SEQ_ID = {businessId}";
using (var cn = _connectionBuilder.GetUpdaterConnection())
{
using (var cmd = _connectionBuilder.GetCommand(sql, cn))
{
cn.Open();
var transaction = cn.BeginTransaction(IsolationLevel.ReadCommitted);
cmd.Transaction = transaction;
//cmd.Parameters.Add("appId", appId);
//cmd.Parameters.Add("businessId", businessId);
//cmd.Parameters.Add("entitlementTypeId", entitlementTypeId);
//cmd.Parameters.Add("lastUpdatedBy", sso);
var rows = cmd.ExecuteNonQuery();
transaction.Commit();
return rows;
}
}
}
I suspect you are binding parameters by position rather than name.
By position, you'd be putting appId first into entitlement_type_seq_id. Then BusinessId into last_Updated_By, entitlementTypeId into app_seq_id and lastUpdatedBy into business_seq_id.
https://docs.oracle.com/cd/B19306_01/win.102/b14307/OracleCommandClass.htm#i997666
Either you have to set
cmd.BindByName = true;
because default value for BindByName property is false, which means the parameters are bound by position.
Or you have to use the same order of parameters as they appear in your statement, i.e.
cmd.Parameters.Add("entitlementTypeId", entitlementTypeId);
cmd.Parameters.Add("lastUpdatedBy", sso);
cmd.Parameters.Add("appId", appId);
cmd.Parameters.Add("businessId", businessId);
btw, usually OracleParameter are added like this:
cmd.Parameters.Add("entitlementTypeId", OracleDbType.Int32, ParameterDirection.Input).Value = entitlementTypeId;
cmd.Parameters.Add("lastUpdatedBy", OracleDbType.Varchar2, ParameterDirection.Input).Value = entitlementTypeId;
cmd.Parameters.Add("appId", OracleDbType.Int32, ParameterDirection.Input).Value = appId;
cmd.Parameters.Add("businessId", OracleDbType.Int32, ParameterDirection.Input).Value = businessId;
I assume for simple data types like numbers of string the syntax does not matter, however other data type (e.g. Date) may fail if you simply use cmd.Parameters.Add(string name, object val).

ODP.Net Managed API - Array Binding with strings > 1000 characters

When using the ODP.Net managed API, when using array binding to insert data into a column of type VARCHAR2(4000), and a string length of a row value in our array is greater than 1000 characters, the following exception is thrown:
ORA-01461: can bind a LONG value only for insert into a LONG column
string sql = "INSERT INTO STAGING(\"COLUMN1\") VALUES (:COLUMN1)";
using (OracleCommand cmd = connection.CreateCommand())
{
cmd.CommandText = sql;
cmd.CommandType = CommandType.Text;
cmd.BindByName = true;
cmd.ArrayBindCount = dt.Rows.Count;
var p = new OracleParameter { ParameterName = parameterName.ToUpper() };
p.OracleDbType = OracleDbType.Varchar2;
p.Value = dt.AsEnumerable().Select(c => (!c.IsNull(fieldName) ? c.Field<T>(fieldName) : default(T))).ToArray();
cmd.Parameters.Add(p);
cmd.ExecuteNonQuery();
}
We currently define our parameters as:
p.OracleDbType = OracleDbType.Varchar2;
I tried to use this instead, but still run into the same issue:
p.OracleDbType = OracleDbType.Clob;
Also tried to set a size on the length of the Varchar2 as follows, but still have the same issue.
p.OracleDbType = OracleDbType.Varchar2;
p.Size = 4000;
Also tried this, with no luck:
string sql = "INSERT INTO STAGING(\"COLUMN1\") VALUES (CAST(:COLUMN1 AS VARCHAR2(4000))";
Any ideas?
This appears to be a similiar issue: https://community.oracle.com/thread/3649551
Update
I suspected that maybe there was some sort of character set issue, which made the length longer than expected, so to rule this out, I reduced the column length of the table that we're trying to insert data into down to VARCHAR2(1000), assuming that this would make the maximum allowable character length to be 250 - this is not the case though. The maximum that is working before this exception is thrown is still 1000.
Update 2
I've found an oracle patch which may resolve this issue. I will try and get this patch and verify. https://support.oracle.com/epmos/faces/PatchDetail?patchId=20361140&requestId=18735492
Update 3
The oracle patch didn't fix the issue for me. I tried to iterate through all of the parameter bind statuses, but they all indicate a success.
catch (Exception ex)
{
foreach (OracleParameter p in cmd.Parameters)
{
foreach (var s in p.ArrayBindStatus)
{
if (s != OracleParameterStatus.Success)
{
}
}
}
}
Update 4
Seems that this is a bug in the Oracle Managed API, here's a sample class that can reproduce the issue.
namespace OracleBindError
{
using Oracle.ManagedDataAccess.Client;
using System.Data;
using System.Linq;
class Program
{
static void Main(string[] args)
{
string testTable = "BIND_TEST_TABLE";
string connString = "[conn string here]";
string dropTable =
#"DECLARE pEXISTS NUMBER;
BEGIN
SELECT COUNT(*) INTO pEXISTS FROM USER_TABLES WHERE TABLE_NAME = '" + testTable + #"';
IF(pEXISTS > 0) THEN
EXECUTE IMMEDIATE 'DROP TABLE " + testTable + #"';
END IF;
EXECUTE IMMEDIATE 'CREATE TABLE " + testTable + #" (COLUMN1 VARCHAR2(4000), COLUMN2 VARCHAR2(4000))';
END;";
string[] greaterThanOneThousand = new string[] {
"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijkldfdffd",
};
string insertStatement = "INSERT INTO " + testTable + "(\"COLUMN1\",\"COLUMN2\") VALUES (:COLUMN1,:COLUMN2)";
using (OracleConnection conn = new OracleConnection(connString))
{
conn.Open();
OracleCommand dropCmd = new OracleCommand(dropTable, conn);
dropCmd.ExecuteNonQuery();
using (OracleCommand cmd = conn.CreateCommand())
{
cmd.CommandText = insertStatement;
cmd.CommandType = CommandType.Text;
cmd.BindByName = true;
cmd.ArrayBindCount = greaterThanOneThousand.Length;
var p = new OracleParameter { ParameterName = "COLUMN1" };
p.OracleDbType = OracleDbType.Varchar2;
p.Value = greaterThanOneThousand.ToArray();
cmd.Parameters.Add(p);
var p2 = new OracleParameter { ParameterName = "COLUMN2" };
p2.OracleDbType = OracleDbType.Varchar2;
p2.Value = new string[] { null };
cmd.Parameters.Add(p2);
cmd.ExecuteNonQuery();
}
conn.Close();
}
}
}
}
Found work-around
If I change the OracleDbType from Varchar2 to NVarchar2 in my parameters it works.
var p = new OracleParameter { ParameterName = "COLUMN1" };
p.OracleDbType = OracleDbType.NVarchar2;
p.Value = greaterThanOneThousand.ToArray();
cmd.Parameters.Add(p);
var p2 = new OracleParameter { ParameterName = "COLUMN2" };
p2.OracleDbType = OracleDbType.Varchar2;
p2.Value = new string[] { " " };
cmd.Parameters.Add(p2);
Work-Around
The work-around is to use NVARCHAR2 in the parameter on the .net side.
You are assigning array of type "T" into value. Whereas, the database expects it to be VARCHAR2(4000), which is equivalent to string. Try converting the value to string.

Call oracle stored function

I try to call my oracle function, but for some reason i get wiered results from it.
This is my C# code :
using (OracleConnection _conn = new OracleConnection("Data Source=(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=10.20.190.2)(PORT=1521)))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=DBIDB)));User Id=blng;Password=blng;"))
{
using (OracleCommand cmd = new OracleCommand())
{
_conn.Open();
cmd.Connection = _conn;
cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.CommandText = "PKG_update_switch.checkexistsinswitch";
cmd.Parameters.Add("phone", OracleDbType.Varchar2, ParameterDirection.Input).Value = phoneToQuery;
cmd.Parameters.Add("res", OracleDbType.Int32, ParameterDirection.ReturnValue);
cmd.ExecuteNonQuery();
result = cmd.Parameters["res"].Value.ToString();
Debug.WriteLine("---" + result);
if (result.Equals("null"))
message = "Didnt find number";
else
message = "Found " + phoneToQuery + " in " + result;
MessageBox.Show(message, "Check Phone Exists",
MessageBoxButtons.OKCancel, MessageBoxIcon.Asterisk);
_conn.Close();
}
}
As a result i always get 0, witch is imposible.
Oracle function:
function checkExistsInSwitch(phone in varchar2) RETURN integer is
tmp varchar2(100):='';
begin
for t in (select c.re_collection_id from re_collection_values c where c.start_range = phone)
loop
----- check that the number is from folder number 2
begin
select o.network_identifier into tmp from operators o where o.switch_folder_id = t.re_collection_id;
return 11;--tmp;
exception
when others then
null;
end;
end loop;
return 11;--'';
end;
this is very wiered, for a stored procedure i get good results, this only happend to my with the stored functions.

Stored Procedures with Mysql connector

I'm trying to call a simple stored procedure in c# 2010.
With only a IN argument it's ok, but now with a OUT argument it's not working.
In phpmyadmin :
drop procedure if exists insert_artist;
delimiter $$
create procedure insert_student(IN name VARCHAR(100), OUT id INT)
begin
insert into student(name) values(name);
set id = last_insert_id();
end$$
delimiter ;
Then using
call insert_student("toto",#id);
select #id;
It's working fine.
Now, in c# :
using (MySqlConnection connection = new MySqlConnection(connectionString))
{
connection.Open();
using (MySqlCommand command = connection.CreateCommand())
{
command.CommandText = "insert_student";
command.CommandType = System.Data.CommandType.StoredProcedure;
command.Parameters.AddWithValue("#name", "xxxx");
command.Parameters.AddWithValue("#id",MySqlDbType.Int32);
command.ExecuteNonQuery();
Console.WriteLine("**** " + command.Parameters["#id"].Value);
}
}
Gives me an exception when executing ExecuteNonQuery() :
OUT or INOUT argument 2 for routine insert_student is not a variable or NEW pseudo-variable in BEFORE trigger
The same thing without the out argument in the stored procedure is working fine.
Where is my mistake?
A fuller example:
if (this.OpenConnection() == true)
{
MySqlCommand cmd = new MySqlCommand(nameOfStoredRoutine, connection);
cmd.CommandType = CommandType.StoredProcedure;
//input parameters
for (int i = 0; i < (parameterValue.Length / 2); i++)
{
cmd.Parameters.AddWithValue(parameterValue[i, 0], parameterValue[i, 1]);
cmd.Parameters[parameterValue[i, 0]].Direction = ParameterDirection.Input;
parameterList = parameterList + parameterValue[i,0] + " " + parameterValue[i,1] + " ";
}
//single output parameter
cmd.Parameters.AddWithValue("#output", MySqlDbType.Int32);
cmd.Parameters["#output"].Direction = ParameterDirection.Output;
cmd.ExecuteNonQuery(); //Execute command
this.CloseConnection(); //close connection
return Convert.ToInt32(cmd.Parameters["#output"].Value.ToString());
my below code works
pls check if it's ok for you.
InsertQuery = New MySqlCommand("xxxxxx")
InsertQuery.Connection = Connection
InsertQuery.CommandType = Data.CommandType.StoredProcedure
InsertQuery.Parameters.AddWithValue("IN_xxx", str_xxxx)
InsertQuery.Parameters.Add("OUT_LastID", MySqlDbType.Int32).Direction = ParameterDirection.Output
IQ = InsertQuery.ExecuteReader()
IQ.Read()
LASTID = InsertQuery.Parameters("OUT_LastID").Value

Categories