I know there are a couple of other questions on here with the exact same issue, but I am 100% positive I don't have any type of permissions issue. The procedure executes fine from the query editor, but for some reason I can't get this proc to execute from a very simple ASP.net page. I should note this is my first attempt at creating an Oracle Proc.
Here is my code that calls the proc (just trying to call it and force results into the label)
string oradb = "connection string here";
OracleConnection conn = new OracleConnection(oradb);
OracleCommand cmd = new OracleCommand();
cmd.Connection = conn;
cmd.CommandText = "x.GETCURSORS";
cmd.CommandType = CommandType.StoredProcedure;
OracleParameter ACTNUM = new OracleParameter();
ACTNUM.OracleDbType = OracleDbType.Decimal;
ACTNUM.Direction = ParameterDirection.Input;
ACTNUM.Value ="12345";
cmd.Parameters.Add(ACTNUM);
OracleParameter REJECTS_C = new OracleParameter();
REJECTS_C.OracleDbType = OracleDbType.RefCursor;
REJECTS_C.Direction = ParameterDirection.Output;
cmd.Parameters.Add(REJECTS_C);
try
{
conn.Open();
OracleDataReader objReader = cmd.ExecuteReader();
Label3.Text = objReader.ToString();
}
catch (Exception ex)
{
Label3.Text = string.Format("Exception: {0}", ex.ToString());
}
Package specification:
PACKAGE "x"."REJECTS_DATA" IS
PROCEDURE "GETCURSORS" (
"ACTNUM" IN NUMBER,
"REJECTS_C" OUT SYS_REFCURSOR);
END "REJECTS_DATA";
Package body:
PACKAGE BODY "x"."REJECTS_DATA" IS
PROCEDURE "GETCURSORS" (
"ACTNUM" IN NUMBER,
"REJECTS_C" OUT SYS_REFCURSOR) IS
BEGIN
OPEN REJECTS_C FOR SELECT * FROM x.a
WHERE x.a.ACCOUNT = ACTNUM;
END "GETCURSORS";
END "REJECTS_DATA";
Assuming that the schema name is X, the package name is REJECTS_DATA, and the procedure name is GETCURSORS, at a minimum, the command would need to be
cmd.CommandText = "x.REJECTS_DATA.GETCURSORS";
If you are actually using case-sensitive identifers in PL/SQL (which I would strongly suggest avoiding), you would need to use case-sensitive identifiers in the procedure name as well.
We faced the same issue in our code and had to keep SCHEMA_NAME out of our proc call in C#, i.e. PACKAGE_NAME.PROC_NAME. We resolved this by creating a Synonym in the database with the SCHEMA_NAME
Related
I am trying to call a stored procedure with a string as parameter (VARCHAR (MAX)) but again and again it tells my #args parameter is not when it certainly is. This is my test procedure:
IF OBJECT_ID ( 'TEST', 'P' ) IS NOT NULL
DROP PROCEDURE TEST;
GO
CREATE PROCEDURE TEST (#args varchar (max)) AS
BEGIN
EXEC sp_execute_external_script
#language = N'R'
, #script = N'OutputDataSet <- as.data.frame(...);'
, #params = N'#args varchar(max)'
, #args = #args
WITH RESULT SETS ((...));
RETURN 0;
END
If I call it from management studio, it works:
SET LANGUAGE ENGLISH
EXEC dbo.TEST #args = 'long string'
GO
but not through C#
public static void Main()
{
Console.WriteLine("Connection test!");
Console.WriteLine("Press ESC to stop");
string ConnectionString = "...";
SqlConnection conn = new SqlConnection(ConnectionString);
SqlCommand cmd = new SqlCommand("TEST");
SqlDataReader rdr = null;
string args = "very long string";
cmd.CommandType = CommandType.StoredProcedure;
cmd.Connection = conn;
cmd.Parameters.Add("#args", SqlDbType.VarChar, -1).Value = args;
conn.Open();
var returnParameter = cmd.Parameters.Add("#ReturnVal", SqlDbType.Int);
returnParameter.Direction = ParameterDirection.ReturnValue;
try { cmd.ExecuteNonQuery(); } // #args is not a parameter for TEST Procedure
catch (SqlException ex)
I am not reusing any parameter which is just a varchar(max). Any ideas?
Finally I found the error which was extremely silly.
Short answer: added the SQL USE statement before dropping and creating the proc.
USE myDB;
GO
Long answer: It turns out I have 2 DBs and I was creating the SP in master but I had another procedure in my testing DB. So although I deleted the SP, there was another one in the other DB with the same name but different parameters, hence the error. As I could not understand why #args was incorrect, I listed the SP params (https://stackoverflow.com/a/3038470/2846161, https://stackoverflow.com/a/3038530/2846161) and it turned out that the procedure was listed even being deleted, therefore it was replicated.
From C# Code, I'm trying to call a PACKAGE.PROCEDURE() from Oracle. In this simple example I should get one value from the procedure call, but all I get is error:
wrong number or types of arguments in call to 'RETURN_NUM'
The procedure is declared as follows:
PROCEDURE return_num(xNum OUT NUMBER) AS
BEGIN
xNum:= 50;
dbms_output.put_line('hello world ' || xNum);
END;
C# code:
Oraclecon.Open();
OleDbCommand myCMD = new OleDbCommand("TEST.return_num", Oraclecon);
myCMD.CommandType = CommandType.StoredProcedure;
myCMD.Parameters.Add("xNum", OleDbType.Numeric);
OleDbDataReader myReader;
myReader = myCMD.ExecuteReader();
Can some one please point out what I'm doing wrong. Then in a real scenario I would like to call a procedure that returns a set of values from a custom Type, such as:
TYPE r_interface_data IS RECORD
(
object_id VARCHAR2(16),
obj_type VARCHAR2(32)
);
TYPE t_interfase_data IS TABLE OF r_interface_data;
How can I approach that. Thanks!
UPDATE: In my particular case I ended-up doing the following approach
using (OleDbCommand cmd = new OleDbCommand("PACKAGE.procedure_name"))
{
cmd.CommandType = CommandType.StoredProcedure;
SqlManager sqlManager = new SqlManager();
return sqlManager.GetDataSet(cmd);
}
I don't think you're that far off... try this:
OracleCommand cmd = new OracleCommand("return_num", Oraclecon);
cmd.Parameters.Add(new OracleParameter("xNum", OracleDbType.Decimal,
ParameterDirection.Output));
cmd.CommandType = CommandType.StoredProcedure;
cmd.ExecuteNonQuery();
OracleDecimal d = (OracleDecimal)cmd.Parameters[0].Value;
double result = d.ToDouble();
result now contains the out parameter from the procedure.
I think your problem is you were attempting to use a DbDataReader on a stored procedure. DbDataReader is for queries.
Also, I used ODP.net -- that may or may not have contributed to your issue, that you were using Ole.
I am populating a text box with the returned value of a function, but it doesn't work if I run the sql code inside the function. I can remove the sql related code and it works. so i'm stumped.
And by "doesn't work" i mean that the text box never gets populated with anything. it remains blank.
thanks
public string CreateResident()
{
string result = "hmm";
SqlConnection sqlConnection = new SqlConnection("Server=DELLXPS\\SQLEXPRESS; Initial Catalog=Warren_SEINDATASYSTEMS; Integrated Security=true;");
SqlCommand cmd = new SqlCommand();
cmd.CommandText = "INSERT INTO [dbo].[NewUsers]([ResidentAccountNumber],[ResidentName],[ResidentAddress],[NumberOfVisitors],[TempPass],[Role])VALUES(#ResidentAccountNumber,#ResidentName,#ResidentAddress,#NumberOfVisitors,(select cast((Abs(Checksum(NewId()))%10) as varchar(1)) + char(ascii('a')+(Abs(Checksum(NewId()))%25)) + char(ascii('A')+(Abs(Checksum(NewId()))%25)) + left(newid(),5)),'resident')";
cmd.CommandType = CommandType.Text;
cmd.Connection = sqlConnection;
SqlParameter ResidentAccountNumber = new SqlParameter();
ResidentAccountNumber.ParameterName = "#ResidentAccountNumber";
ResidentAccountNumber.Value = txtboxResidenetAccountNumber.Text.Trim();
cmd.Parameters.Add(ResidentAccountNumber);
SqlParameter ResidentName = new SqlParameter();
ResidentName.ParameterName = "#ResidentName";
ResidentName.Value = txtboxResidentName.Text.Trim();
cmd.Parameters.Add(ResidentName);
SqlParameter ResidentAddress = new SqlParameter();
ResidentAddress.ParameterName = "#ResidentAddress";
ResidentAddress.Value = txtboxResidentAddress.Text.Trim();
cmd.Parameters.Add(ResidentAddress);
SqlParameter NumberOfVisitors = new SqlParameter();
NumberOfVisitors.ParameterName = "#NumberofVisitors";
NumberOfVisitors.Value = txtboxNumberOfVisitors.Text.Trim();
cmd.Parameters.Add(NumberOfVisitors);
try
{
sqlConnection.Open();
result = (string)cmd.ExecuteScalar();
sqlConnection.Close();
}
catch (Exception ex)
{
result = ex.Message;
}
return result;
}
protected void btnCreateResident_Click(object sender, EventArgs e)
{
txtboxTempPassword.Text = CreateResident();
}
Your SQL is wrong and you have a lot of problems but I want to show you a way to make your code more readable. Format it like this:
cmd.CommandText = #"INSERT INTO [dbo].[NewUsers] ([ResidentAccountNumber],[ResidentName],[ResidentAddress], NumberOfVisitors],[TempPass], Role])
VALUES(
#ResidentAccountNumber,
#ResidentName,
#ResidentAddress,
#NumberOfVisitors,
(select cast((Abs(Checksum(NewId()))%10) as varchar(1)) + char(ascii('a')+(Abs(Checksum(NewId()))%25)) + char(ascii('A')+(Abs(Checksum(NewId()))%25)) + left(newid(),5)),
'resident')";
cmd.CommandType = CommandType.Text;
cmd.Connection = sqlConnection;
We know that a select in a VALUES constructor is not legal so that is one problem.
Also having a SELECT without a from seems strange -- did you copy your code correctly?
You are using ExecuteScalar -- do you know what that does? It shouldn't include a query that includes INSERT query.
I'm guessing you probably want a stored procedure.
I would suggest do not write query in C# code, you must use Stored Procedure for the same purpose.
If you want your query to return some id, primary key or some value then you must write query for that after your insert query.
you can use the following keywords in your select query,if you want to return id from table.
SCOPE_IDENTITY returns the last IDENTITY value inserted into an IDENTITY column in the same scope.
IDENT_CURRENT returns the last identity value generated for a specific table in any session and any scope.
##IDENTITY returns the last identity value generated for any table in the current session, across all scopes.
If you want to return only one record then use ExecuteScalar else you can use ExecuteReader.
If your only purpose is to insert data into the table then you should use ExecuteNonQuery.
With the help of comments I went with ExecuteReader instead of the ExecuteScaler. And changed the statement to return a value
INSERT INTO [table] ([fields]) OUTPUT Inserted.MyColumn VALUES(values)
C# Code:
reader = cmd.ExecuteReader();
try
{
while (reader.Read())
{
result = reader[0].ToString();
}
}
catch (Exception ex)
{
result = ex.Message;
}
return result;
I have a simple package defined as follows:
CREATE OR REPLACE PACKAGE wvParty IS
TYPE refParties IS REF CURSOR;
END wvParty;
CREATE OR REPLACE PACKAGE BODY wvParty IS
PROCEDURE proc_GetParties(
p_party_name IN OUT VARCHAR2,
x_party_info OUT refParties
)
IS
BEGIN
p_party_name := '%'||p_party_name||'%';
OPEN x_party_info FOR
SELECT party_id, party_number, party_type, party_name,
person_first_name, person_middle_name, person_last_name,
known_as, known_as2, known_as3, known_as4, known_as5
FROM hz_parties
WHERE 1=1
AND party_name LIKE p_party_name;
END;
END wvParty;
It gets created in the oracle db with no errors. In my code, I'm trying to call it using:
try
{
OracleConnection conn = new OracleConnection(_connStr);
conn.Open();
OracleCommand cmd = conn.CreateCommand();
cmd.CommandText = "wvParty.proc_GetParties";
cmd.CommandType = CommandType.StoredProcedure;
OracleParameter partyName = new OracleParameter();
partyName.ParameterName = "p_party_name";
partyName.OracleDbType = OracleDbType.Varchar2;
partyName.Direction = ParameterDirection.InputOutput;
partyName.Value = "Bubba";
cmd.Parameters.Add(partyName);
OracleParameter refParties = new OracleParameter();
refParties.ParameterName = "x_party_info";
refParties.OracleDbType = OracleDbType.RefCursor;
refParties.Direction = ParameterDirection.Output;
cmd.Parameters.Add(refParties);
OracleDataReader rdr = cmd.ExecuteReader();
Yet, when I do I get the error:
PLS-00302: component 'PROC_GETPARTIES' must be declared.
So I'm at a loss. I've created the proc as part of the package, I've declared it as I believe I should but I'm having little success resolving this. Any suggestion?
I can't comment on the C# side of things, but there are a some problems on the Oracle side, like:
proc_GetParties is defined in the package body, but is not declared in the package specification. This means that it's not visible outside the package body. This explains why you are getting the PLS-00302 error.
The 1=1 condition is not needed in the WHERE clause.
Do you really want to change the value of p_party_name within the procedure and have that change to be visible to the caller? If not, it might be better to leave p_party_name unchanged and change the LIKE condition to party_name LIKE '%' || p_party_name || '%'.
I am VERY new when it comes to stored procedures and .NET, so I apologize in advance. I have a stored procedure that I am trying to use and I keep getting this error..."wrong number or types of arguments in call to 'COPY_ACCOUNT'". I am not sure why. Below is my stored procedure code followed by my C#.NET code. Any help is GREATLY appreciated. PLEASE.
create or replace procedure abstract_names.copy_account(r_rows_copied out int,
ar_old_acct in abn_headings.acct_no%type,
ar_new_acct in abn_headings.acct_no%type)
is
cnt int := 0;
begin
r_rows_copied := 0;
for r in (select heading from abn_headings where acct_no = ar_old_acct) loop
copy_heading(cnt, ar_old_acct, r.heading, ar_new_acct);
r_rows_copied := r_rows_copied + cnt;
end loop;
dbms_output.put_line('called abstract_names.copy_account '||to_char(r_rows_copied));
return; end;
Then my C#.NET code...
using System.Data.OracleClient;
try
{
conn.Open();
OracleCommand cmd = new OracleCommand();
cmd.Parameters.Add("r_rows_copied", OracleType.Int32).Direction = ParameterDirection.Output;
cmd.Parameters.Add("ar_from_acct", OracleType.VarChar).Value = accountNumberDropDownList.SelectedValue.ToString();
cmd.Parameters.Add("ar_to_acct", OracleType.VarChar).Value = copyAccountDDL.SelectedValue.ToString();
cmd = new OracleCommand("abstract_names.copy_account", conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.ExecuteNonQuery();
conn.Close();
/*
abstract_names.copy_account(r_rows_copied out int,
ar_from_acct in abn_headings.acct_no%type,
ar_to_acct in abn_headings.acct_no%type)
*/
}
finally
{
if (conn != null)
conn.Close();
}
My connection string is correct because I use it else where in my code and it works. The commented section is the stored procedure i am trying to use obviously. Please help me!
Just looking at your code and not being familiar with this OracleCommand object, it looks like you're creating parameters and then creating a new object in the middle wiping out all your parameter additions. Create a new object from the connection and then add your parameters. Attempting a stab at better code below. Also I would use using statements for any conneciton,commnand objects to ensure they get closed and disposed.
Edit: Didn't look too deep, my fault. It looks like the parameter names weren't matching up in the stored procedure and the .net code. Also since you're returning a value, I would use the ExecuteScalar method, ExeuteNonQuery won't return any data.
cmd = new OracleCommand("abstract_names.copy_account", conn);
cmd.Parameters.Add("r_rows_copied", OracleType.Int32).Direction = ParameterDirection.Output;
cmd.Parameters.Add("ar_old_acct ", OracleType.VarChar).Value = accountNumberDropDownList.SelectedValue.ToString();
cmd.Parameters.Add("ar_new_acct", OracleType.VarChar).Value = copyAccountDDL.SelectedValue.ToString();
cmd.CommandType = CommandType.StoredProcedure;
object value = cmd.ExecuteScalar();
conn.Close();
You assign a new instance to your cmd variable, then you lose reference to what you had done.
Here:
cmd.Parameters.Add("ar_to_acct", OracleType.VarChar).Value = copyAccountDDL.SelectedValue.ToString();
cmd = new OracleCommand("abstract_names.copy_account", conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.ExecuteNonQuery();
conn.Close();
This is the wrong line:
cmd = new OracleCommand("abstract_names.copy_account", conn);
Just by looking at your code, I think you should simply remove that line and it should be OK.