Calling stored procedure in C# - c#

I have this stored procedure
create or replace procedure get_login(p_username in varchar2)
is
begin
select USERPASSWORD
from LOGIN
where USERNAME = p_username;
end;
and I try to call it in C# with this
public string login(string username)
{
try
{
conn.Open();
OracleCommand cmd = new OracleCommand("get_login",conn);
cmd.CommandType = CommandType.StoredProcedure;
OracleParameter obja = new OracleParameter("P_USERNAME", OracleDbType.Varchar2, ParameterDirection.Input);
obja.Value = username;
obja.UdtTypeName = "varchar2";
// OracleParameter objb = new OracleParameter("P_USERPASSWORD", OracleDbType.Varchar2, ParameterDirection.Output);
cmd.Parameters.Add(obja);
Login = cmd.ExecuteScalar().ToString();
}
catch(Exception ex)
{
throw ex;
}
finally
{
conn.Close();
}
return Login;
}
but when I run it I get this error:
ORA-06550: Regel 1, kolom 7:
PLS-00306: wrong number or types of arguments in call to 'GET_LOGIN'.
ORA-06550: Regel 1, kolom 7:
PL/SQL: Statement ignored.
System.Exception {Oracle.DataAccess.Client.OracleException}
I'm not really sure what I'm doing wrong here. It might be the procedure but testing that in the database works. I probably did something wrong and I don't know what.
Also if I may ask what does obja.UdtTypeName mean? I followed an example of a friend so I'm not really sure.
P.S: English is not my first language so if I got some terms wrong I'm sorry
edit:
public DBConnect()
{
conn = new OracleConnection();
String pcn = "login";
String pw = "pass";
conn.ConnectionString = "User Id=" + pcn + ";Password=" + pw + ";Data Source=" + "//ipofdatabase" + ";";
}
edit2:
create or replace
procedure get_login(p_username in varchar2)
is
begin
select USERPASSWORD from LOGIN where USERNAME = p_username;
end;
when i do that i get this error:
Error(4,1): PLS-00428: an INTO clause is expected in this SELECT statement

You have only added 1 parameter:
OracleParameter objb = new OracleParameter("P_USERPASSWORD", OracleDbType.Varchar2, ParameterDirection.Output);
cmd.Parameters.Add(obja);
should be:
OracleParameter objb = new OracleParameter("P_USERPASSWORD", OracleDbType.Varchar2, ParameterDirection.Output);
cmd.Parameters.Add(obja);
objb.Size = 255;
cmd.Parameters.Add(objb);
To get the value, change:
Login = cmd.ExecuteScalar().ToString();
To this:
cmd.ExecuteNonQuery();
Login = objb.Value.ToString();

Related

How do I execute a SqlDataReader after sqlInsertCmd.ExecuteNonQuery

I am inserting a data row into my SQL Server database and then I want to query the data to get the unique identifier from the inserted row but my SqlDataReader is returning an empty dataset. I am thinking it maybe that the transaction hasn't been committed or something like that but I am not sure. I do not get an error.
Here is my code:
try
{
strQuery = "INSERT INTO clientnames VALUES(NEWID(),'" + txtACLastName.Text + "','" + txtACFirstName.Text + "'," + 1 + ")";
using (SqlCommand sqlInsertCmd = new SqlCommand(strQuery, sqlConn))
{
intQueryResult = sqlInsertCmd.ExecuteNonQuery();
if (intQueryResult == 0)
{
blnSuccess = false;
goto InsertClientNamesError;
}
else
{
blnSuccess = true;
}
sqlInsertCmd.Dispose();
}
if (blnSuccess)
{
strQuery = "select clientID from clientnames where firstname = '" + txtACFirstName.Text + "' and lastname = '" + txtACLastName.Text + "'";
using (SqlCommand sqlSelectCmd = new SqlCommand(strQuery, sqlConn))
{
SqlDataReader sqlDataRead = sqlSelectCmd.ExecuteReader();
while (sqlDataRead.Read())
{
strClientID = sqlDataRead.ToString();
}
sqlDataRead.Close();
sqlSelectCmd.Dispose();
}
}
}
catch (Exception exQuery)
{
System.Windows.MessageBox.Show("InsertClientNames: Error, " + exQuery.Message + ", has occurred.");
}
You are not getting the desired result because perhaps the SqlConnection is not opened explicitly (just a guess hard to tell without having full code). But this link shows you how to read from reader --> https://msdn.microsoft.com/en-us/library/haa3afyz(v=vs.110).aspx
But I suggest that you Please do not do it this way. Reason is you are making Two round trips to the DB Server when only one would have done the job for you IF you were using stored procedures. Also you are exposing yourselves to SQL Injection attacks as you are not parameterizing your queries.
Stored procedure:
CREATE PROCEDURE dbo.INS_clientnames
(
#FirstName varchar(100),
#LastName varchar(100),
#NewID int out
)
AS
BEGIN
Declare #Err int
set #NewID = NewID() -- Get the New ID and store it in the variable ( #NewID ) that the SP will return back to the caller
INSERT INTO clientnames values (#NewID , #FirstName , #LastName)
SET #Err = ##ERROR
IF #Error <> 0 -- Check If there was an error
Begin
SET #NewID = -1 -- Indicates that there was an error. You could log this into a Log Table with further details like error id and name.
END
RETURN
END
C# code to execute the above stored procedure and get the NewID:
using(SqlConnection conn = new SqlConnection(connectionString ))
{
using(SqlCommand cmd = new SqlCommand("dbo.INS_clientnames", conn))
{
cmd.CommandType = CommandType.StoredProcedure;
// set up the parameters that the Stored Procedure expects
cmd.Parameters.Add("#FirstName", SqlDbType.VarChar, 100);
cmd.Parameters.Add("#LastName" , SqlDbType.VarChar, 100);
cmd.Parameters.Add("#NewId" , SqlDbType.Int).Direction = ParameterDirection.Output;
// set parameter values that your code will send to the SP as parameter values
cmd.Parameters["#FirstName"].Value = txtACFirstName.Text ;
cmd.Parameters["#LastName"].Value = txtACLastName.Text ;
// open connection and execute stored procedure
conn.Open();
cmd.ExecuteNonQuery();
// read output value from #NewId
int NewID = Convert.ToInt32(cmd.Parameters["#NewId"].Value);
}
}
Add the following line to your stored procedure that inserts the record
SELECT SCOPE_IDENTITY()
This will return the last identity value inserted in that table.
And use cmd.ExecuteScalar() instead of ExecuteNonQuery()
ExecuteScalar() executes the query, and returns the first column of the first row in the result set returned by the query. Additional columns or rows are ignored. [More info][1]
I see two approaches to do this:
either you generate the new GUID on the client side in your C# code and pass it into the query - then you already know what the new id is going to be, so you don't need to do a second query to get it:
you create your GUID on the server side and return it to the caller using the OUTPUT clause in your query
Approach #1:
// define connection string and query
string connStr = "--your connection string here--";
string query = "INSERT INTO dbo.Clients(ClientID, FirstName, LastName) VALUES(#ID, #First, #Last);";
using (SqlConnection conn = new SqlConnection(connStr))
using (SqlCommand cmd = new SqlCommand(query, conn))
{
// create the GUID in C# - this is the ID - no need to go get it again - this *IS* the id
Guid id = Guid.NewGuid();
// set the parameters
cmd.Parameters.Add("#ID", SqlDbType.UniqueIdentifier).Value = id;
cmd.Parameters.Add("#First", SqlDbType.VarChar, 50).Value = "Peter";
cmd.Parameters.Add("#Last", SqlDbType.VarChar, 50).Value = "Miller";
// open connection, execute query, close connection
conn.Open();
cmd.ExecuteNonQuery();
conn.Close();
}
Approach #2:
// define connection string and query
string connStr = "--your connection string here--";
// query has an "OUTPUT" clause to return a newly inserted piece of data
// back to the caller, just as if a SELECT had been issued
string query = "INSERT INTO dbo.Clients(ClientID, FirstName, LastName) OUTPUT Inserted.ClientID VALUES(NEWID(), #First, #Last);";
using (SqlConnection conn = new SqlConnection(connStr))
using (SqlCommand cmd = new SqlCommand(query, conn))
{
// set the parameters - note: you do *NOT* send in a GUID value - the NEWID() will create one automatically, on the server
cmd.Parameters.Add("#First", SqlDbType.VarChar, 50).Value = "Frank";
cmd.Parameters.Add("#Last", SqlDbType.VarChar, 50).Value = "Brown";
// open connection
conn.Open();
// execute query and get back one row, one column - the value in the "OUTPUT" clause
object output = cmd.ExecuteScalar();
Guid newId;
if (Guid.TryParse(output.ToString(), out newId))
{
//
}
conn.Close();
}

Using Oracle.ManagedDataAccess.Client to return a value from a function to c#

I have the following Function in Oracle:
FUNCTION return_test (p_id varchar2) RETURN VARCHAR2
is
p_return_val VARCHAR2 (500 CHAR) := 'test';
begin
return p_return_val;
end;
I'm trying to get the value into my c# code as follows:
var dbCommand = new OracleCommand();
string retVal;
string Function_query = "PKG_TEST.return_test";
dbConnection = new OracleConnection(ConnString);
dbConnection.Open();
OracleParameterCollection dbParams = dbCommand.Parameters;
dbParams.Add("p_return_val", OracleDbType.Varchar2, System.Data.ParameterDirection.ReturnValue);
dbParams.Add("p_id", OracleDbType.Varchar2, "123", System.Data.ParameterDirection.Input);
OracleCommand cmd;
OracleParameter dbAddParam;
cmd = new OracleCommand(Function_query , dbConnection);
cmd.CommandType = CommandType.StoredProcedure;
foreach (OracleParameter dbParam in dbParams)
{
dbAddParam = (OracleParameter)dbParam.Clone(); // clones all settings
cmd.Parameters.Add(dbAddParam);
}
retVal = cmd.ExecuteScalar().tostring();
The Error while debugging is:
{"ORA-06502: PL/SQL: numeric or value error: character string buffer
too small\nORA-06512: at line 1"}
I never worked with OracleParameterCollection. Usually I add Parameters to OracleCommand one by one.
Anyway, try this one:
OracleParameterCollection dbParams = dbCommand.Parameters;
dbParams.Add("p_return_val", OracleDbType.Varchar2, 500, null, ParameterDirection.ReturnValue);
dbParams.Parameters["p_return_val"].DbType = DbType.String; // Maybe this line is not required at Oracle.ManagedDataAccess. However, you must use it for Oracle.DataAccess
dbParams.Add("p_id", OracleDbType.Varchar2, "123", ParameterDirection.Input);
string Function_query = "BEGIN :p_return_val := PKG_TEST.return_test(:p_id); END;";
cmd = new OracleCommand(Function_query , dbConnection);
cmd.CommandType = CommandType.Text
cmd.Parameters.Add(dbParams);
cmd.ExecuteNonQuery();
retval = cmd.Parameters["p_return_val"].Value;
You cannot use method ExecuteScalar() on a function call, it is used only for result sets, i.e. SELECT ... statements. See Data Provider for .NET Developer's Guide
Thank you Wernfried for your contribution. I will try it out now. In the mean time we found this to work:
string query = "select PKG_TEST.return_test(:x) from dual";
dbParams.Add("x", OracleDbType.Varchar2, QuoteID, System.Data.ParameterDirection.Input);
var result = (string)dbManager.ExecuteScalar(query, dbParams, CommandType.Text);
To me, it seems like its inline SQL which I would always try and avoid, but it worked. Is there any reason I wouldn't use this?

How to call Oracle stored procedure which returns ref cursor

I am trying to call Oracle stored procedure which returns ref cursor, and i need to generate tree view from that returned data. I am new at this and i have two problems.
First problem is that i am not able to call that procedure. I am getting this error: "wrong number or types of arguments in call to 'OBJECT_HIERARCHY'"
And my second problem is that i don't understand how am i gonna get that data when this procedure returns a ref cursor value? There are more then 5000 records in that table and i am not getting that data, but a ref cursor value. Can someone please explain how can i get that data with ref cursor value. I have no experience with Oracle.
This is the procedure definition in oracle:
CREATE OR REPLACE PROCEDURE SAD.object_hierarchy
(nAppId IN NUMBER,
nParentId IN NUMBER DEFAULT -1,
o_cRefCursor OUT SYS_REFCURSOR)
IS
BEGIN
IF NOT o_cRefCursor%ISOPEN THEN
OPEN o_cRefCursor FOR
SELECT
h.PARENT_ID, h.CHILD_ID, h.H_LEVEL,
o.OBJECT_IDENTIFIER, o.OBJECT_TYPE_ID
FROM
(
SELECT
PARENT_ID, CHILD_ID, LEVEL AS H_LEVEL
FROM OBJECT_RELATIONSHIPS
START WITH PARENT_ID = nParentId --> -1 --= 60170
CONNECT BY PRIOR CHILD_ID = PARENT_ID
) h
INNER JOIN
OBJECTS o
ON
o.OBJECT_ID = h.CHILD_ID AND
O.APPLICATION_ID = nAppId;
END IF;
END object_hierarchy;
these are the table field definitions
Column Name Data Type
OBJECT_REL_ID NUMBER (14)
PARENT_ID NUMBER (14)
CHILD_ID NUMBER (14)
OBJECT_IDENTIFIER VARCHAR2 (255 Byte)
OBJECT_TYPE_ID VARCHAR2 (5 Byte)
and this is my code which returns error:
string oradb = "Data Source=(DESCRIPTION="
+ "(ADDRESS=(PROTOCOL=TCP)(HOST=tnt33)(PORT=1521))"
+ "(CONNECT_DATA=(SERVICE_NAME=ORCL)));"
+ "User Id=xxx;Password=xxxxx;";
OracleConnection con = new OracleConnection(oradb);
try
{
con.Open();
OracleCommand cmd = new OracleCommand();
cmd.Connection = con;
cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.CommandText = "SAD.object_hierarchy";
cmd.Parameters.Add("nAppId", OracleDbType.Int16).Value = 1;
OracleParameter oraP = new OracleParameter();
oraP.OracleDbType = OracleDbType.RefCursor;
oraP.Direction = System.Data.ParameterDirection.Output;
cmd.Parameters.Add(oraP);
OracleDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
}
reader.Close();
}
catch (Exception ex)
{
con.Close();
}
Can someone please help me and explain to me why is my code returning this error: "wrong number or types of arguments in call to 'OBJECT_HIERARCHY'"
Example:
string connStr = "Data Source=...";
DataSet dataset = new DataSet();
string connStr = ConfigurationManager.ConnectionStrings["OracleConn"].ToString();
using (OracleConnection objConn = new OracleConnection(connStr))
{
OracleCommand cmd = new OracleCommand();
cmd.Connection = objConn;
cmd.CommandText = "Oracle_PkrName.Stored_Proc_Name";
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("Emp_id", OracleType.Int32).Value = 3; // Input id
cmd.Parameters.Add("Emp_out", OracleType.Cursor).Direction = ParameterDirection.Output;
try
{
objConn.Open();
cmd.ExecuteNonQuery();
OracleDataAdapter da = new OracleDataAdapter(cmd);
da.Fill(dataset);
}
catch (Exception ex)
{
System.Console.WriteLine("Exception: {0}", ex.ToString());
}
objConn.Close();
}
If you're going to provide the OUT, you'll need to provide nParentId as well because .NET isn't going to name those parameters when the statement is sent to the server.
cmd.Parameters.Add("nParentId", OracleDbType.Int16).Value = -1;

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