I'm testing oracle function calls from c#.
I've managed to write stable working test function and it's call.
here it is.
create or replace function abs.test_func(test_in in integer,test_varchar in varchar2)
return integer
is
test_out integer ;
BEGIN
test_out:=test_in;
RETURN test_out;
END;
c# call
using (var cmd = new OracleCommand("abs.test_func", conn1))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(new OracleParameter("test_in", OracleDbType.Int64, test_in, ParameterDirection.Input));
cmd.Parameters.Add(new OracleParameter("test_varchar", OracleDbType.Varchar2, 2000, test_varchar, ParameterDirection.Input));
cmd.Parameters.Add(new OracleParameter("test_out", OracleDbType.Int64, ParameterDirection.ReturnValue));
cmd.ExecuteNonQuery();
JsonResponse.Result = Int32.Parse(cmd.Parameters[0].Value.ToString());
This code works perfectly.
Now I'm just doing the same, just put varchar2 input in front , before integer input.
create or replace function abs.test_func(test_varchar in varchar2, test_in in integer)
return integer
is
test_out integer ;
BEGIN
test_out:=test_in;
RETURN test_out;
END;
c# call
using (var cmd = new OracleCommand("abs.test_func", conn1))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(new OracleParameter("test_varchar", OracleDbType.Varchar2, 2000, test_varchar, ParameterDirection.Input));
cmd.Parameters.Add(new OracleParameter("test_in", OracleDbType.Int64, test_in, ParameterDirection.Input));
cmd.Parameters.Add(new OracleParameter("test_out", OracleDbType.Int64, ParameterDirection.ReturnValue));
cmd.ExecuteNonQuery();
JsonResponse.Result = Int32.Parse(cmd.Parameters[0].Value.ToString());
And my c# throughs error
Input string was not in a correct format.
How can switching variables effect the outcome ????
I had a similar bug, and it was resolved with
alter system set "_qkslvc_extended_bind_sz"=0 scope=spfile;
and restart database.
Probably it was fixed already in newer oracle versions.
What version do you use?
Related
I've been struggling with a call to an Oracle database for over a day now. I have no access to the database other than programmatically, although a DBA was able to give me the following:
desc appowner.member_data_package
PROCEDURE UPDATE_NOTES_V001
Argument Name Type In/Out Default?
------------------------------ ----------------------- ------ --------
TAU_UID_IN VARCHAR2 IN
INCOMING_FUNC_IN VARCHAR2 IN
INCOMING_TEXT_IN VARCHAR2 IN
SYS_SOURCE_IN VARCHAR2 IN
USER_ID_IN VARCHAR2 IN
O_STATUS VARCHAR2 OUT
My code looks like this:
using (var connection = new OracleConnection(connectionString))
{
connection.Open();
OracleCommand command = new OracleCommand
{
Connection = connection,
CommandType = CommandType.StoredProcedure,
CommandText = "appowner.MEMBER_DATA_PACKAGE.UPDATE_NOTES_V001",
BindByName = true
};
command.Parameters.Add(new OracleParameter("O_STATUS", OracleDbType.Varchar2, ParameterDirection.ReturnValue));
command.Parameters.Add(new OracleParameter("TAU_UID_IN", OracleDbType.Varchar2, ParameterDirection.Input)).Value = "7400";
command.Parameters.Add(new OracleParameter("INCOMING_FUNC_IN", OracleDbType.Varchar2, ParameterDirection.Input)).Value = "PROVCOUNT";
command.Parameters.Add(new OracleParameter("INCOMING_TEXT_IN", OracleDbType.Varchar2, ParameterDirection.Input)).Value = "Pypestream testing.";
command.Parameters.Add(new OracleParameter("SYS_SOURCE_IN", OracleDbType.Varchar2, ParameterDirection.Input)).Value = "CRM";
command.Parameters.Add(new OracleParameter("USER_ID_IN", OracleDbType.Varchar2, ParameterDirection.Input)).Value = "jac";
command.ExecuteNonQuery();
Console.WriteLine($"Insert output value is '{command.Parameters["O_STATUS"].Value.ToString()}'");
}
The error I get when I run this is:
ORA-06550: line 1, column 15:
PLS-00306: wrong number or types of arguments in call to 'UPDATE_NOTES_V001'
ORA-06550: line 1, column 7:
PL/SQL: Statement ignored
As far as I can tell I do have the right number and types of arguments, but if somebody wiser than me in the ways of Oracle (which, basically, is anyone) can point out where I messed up that would be awesome.
If that part looks right and the error is a red herring of some sort, what else can I look at? Is there some other way to call this procedure? Keep in mind I have no tools other than Visual Studio 2017. I cannot download any helpful extensions. I have no direct access to the database other than an email to the DBA.
I also confess that I could be on a completely wrong tack here. I'm totally guessing the code to insert values into the Oracle database would look like this based on some examples I've seen here and around the 'net. Any advice to tackle this would be helpful.
The call to the Oracle procedures needs to match the type and order of the parameters of the called procedure. Also, a parameter that returns a value is an OutPut parameter. Your code does not match the parameters of the called procedure, hence the error. Change it to:
using (var connection = new OracleConnection(connectionString))
{
connection.Open();
OracleCommand command = new OracleCommand
{
Connection = connection,
CommandType = CommandType.StoredProcedure,
CommandText = "appowner.MEMBER_DATA_PACKAGE.UPDATE_NOTES_V001",
BindByName = true
};
command.Parameters.Add(new OracleParameter("TAU_UID_IN", OracleDbType.Varchar2, ParameterDirection.Input)).Value = "7400";
command.Parameters.Add(new OracleParameter("INCOMING_FUNC_IN", OracleDbType.Varchar2, ParameterDirection.Input)).Value = "PROVCOUNT";
command.Parameters.Add(new OracleParameter("INCOMING_TEXT_IN", OracleDbType.Varchar2, ParameterDirection.Input)).Value = "Pypestream testing.";
command.Parameters.Add(new OracleParameter("SYS_SOURCE_IN", OracleDbType.Varchar2, ParameterDirection.Input)).Value = "CRM";
command.Parameters.Add(new OracleParameter("USER_ID_IN", OracleDbType.Varchar2, ParameterDirection.Input)).Value = "jac";
command.Parameters.Add(new OracleParameter("O_STATUS", OracleDbType.Varchar2, ParameterDirection.OutPut));
command.ExecuteNonQuery();
Console.WriteLine($"Insert output value is '{command.Parameters["O_STATUS"].Value.ToString()}'");
}
I have a stored procedure . The input is 'id', output 'n'.
But when I try to run it in Visual Studio , I have an error: The value for the output parameter 'n' is absent in the command execution result.
Here is my code:
int id = Convert.ToInt32(this.textBox1.Text);
PgSqlConnection con = new PgSqlConnection();
con.ConnectionString = Properties.Settings.Default.DBConnectionString;
PgSqlCommand cmd = con.CreateCommand();
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "getcountmaterials";
PgSqlParameter param = new PgSqlParameter("n", SqlDbType.Int);
param.Direction = ParameterDirection.Output;
cmd.Parameters.Add(param);
cmd.Parameters.Add(new PgSqlParameter("#id", id));
con.Open();
cmd.ExecuteNonQuery();
string kolvo = cmd.Parameters["n"].Value.ToString();
con.Close();
this.result.Text = kolvo;
Stored Procedure:
CREATE OR REPLACE FUNCTION public.getcountmaterials(id integer)
RETURNS integer AS
$BODY$
declare n integer;
begin n := (select sum(count) from materials_in_warehouses
where id_materials = id);
return n;
end;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
ALTER FUNCTION public.getcountmaterials(integer)
OWNER TO postgres;
I've never used dotConnect for Pg (I am, however, a huge fan of it for Oracle), so I can't verify that I have the syntax right on all of this.
That said, I think I see your core issue. The lines between functions and "stored procedures" is somewhat blurred with Postgresql.
All you really want to do is run a select on the function above. As such, I believe the following will work. I know this would work with NpgSql, and I am hopeful it will translate properly to dotConnect:
PgSqlCommand cmd = new PgSqlCommand("select getcountmaterials(:ID)", con);
cmd.Parameters.AddWithValue("ID", id);
string kolvo = cmd.ExecuteScalar().ToString();
I am trying to perform update action in Visual Studio 2010 ultimate with Windows form as the front end and Oracle 11g express as the back end. I am using c# to code this.
private void update_student(string STUDENT_ID, string STUDENT_NAME, string STUDENT_ADDRESS)
{
con.Open();
String sql = "UPDATE STUDENT SET STUDENT_NAME = :STUDENT_NAME, STUDENT_ADDRESS= :STUDENT_ADDRESS WHERE STUDENT_ID= :STUDENT_ID";
OracleCommand query = new OracleCommand(sql, con);
OracleParameter[] updatestud = new OracleParameter[3];
//updatestud[0] = query.Parameters.Add("STUDENT_ID", OracleDbType.Varchar2, STUDENT_ID, ParameterDirection.Input);
updatestud[0] = query.Parameters.Add("STUDENT_ID", OracleDbType.Int32, STUDENT_ID, ParameterDirection.Input);
updatestud[1] = query.Parameters.Add("STUDENT_NAME", OracleDbType.Varchar2, STUDENT_NAME, ParameterDirection.Input);
updatestud[2] = query.Parameters.Add("STUDENT_ADDRESS", OracleDbType.Varchar2, STUDENT_ADDRESS, ParameterDirection.Input);
query.ExecuteNonQuery();
MessageBox.Show("Row Updated");
con.Close();
}
After performing insertion and retrieval actions I am now trying out Update query.
I couldn't understand the flow of parameters and values of the following code that I have used in my application. I get the following error in the query.ExecuteNonQuery(); line:
ORA-01722: invalid number
I got suggestions to check the Oracle Type. But in spite of the correction, I find the same error.
Even After correcting the Oracle type, I find the same error. Any suggestions?
I am having serious issues trying to get the data back from the SP. I was trying to do it like this:
OracleCommand ora_cmd = new OracleCommand("a6r1.PR_ABC_P_ALTA_TARJETA_PAYWARE", ora_conn);
ora_cmd.BindByName = true;
ora_cmd.CommandType = CommandType.StoredProcedure;
int success= new int();
ora_cmd.Parameters.Add("Lc_Param_Issuer", OracleDbType.Varchar2, issuer, ParameterDirection.Input);
ora_cmd.Parameters.Add("Ln_Param_Valid_Product", OracleDbType.Varchar2, DropDownListProducto.SelectedValue.ToString(), ParameterDirection.Input);
ora_cmd.Parameters.Add("Ln_Param_Total", OracleDbType.Int32, parsed, ParameterDirection.Input);
ora_cmd.Parameters.Add("Lc_Param_User", OracleDbType.Varchar2, user, ParameterDirection.Input);
ora_cmd.Parameters.Add("Lc_Encrypted_Password", OracleDbType.Varchar2, pass, ParameterDirection.Input);
ora_cmd.Parameters.Add("Lc_Exito", OracleDbType.Int32, success, ParameterDirection.Output);
ora_cmd.Parameters.Add("Lc_Error", OracleDbType.Varchar2, errorMessage, ParameterDirection.Output);
But it is not returning anything to the variables sucess or errorMessage. What am I doing wrong? Is there a better way? It works fine when executed directly on Oracle.
It seems you cannot use existing variable as output parameter, try this way instead
ora_cmd.Parameters.Add("Lc_Exito", OracleDbType.Int32).Direction = ParameterDirection.Output;
ora_cmd.ExecuteNonQuery();
if (ora_cmd.Parameters["Lc_Exito"].value == 0)
I have not found anywhere where it documents the whole process in one place, so after hitting my head against the wall and banging it out, here is my version of what I came up with, using one of the output parameters from the OP's code:
OracleParameter param = new OracleParameter();
param = ora_cmd.Parameters.Add("Lc_Exito", OracleDbType.Int32, ParameterDirection.Output); // can assign the direction within the parameter declaration
param.Size = 25; // failed for me if I did not have this - should be the same as the DB field, if exporting a value from the database
ora_cmd.ExecuteNonQuery();
int myLc_ExitoValue = int.Parse(param.Value); // might not need to parse, and might need a .ToString() on param.Value if you do - I was using strings so not sure about OP's exact case
Then the stored procedure needs to be set up to accept the OUT parameter and you must assign to it in the procedure:
create or replace procedure PR_ABC_P_ALTA_TARJETA_PAYWARE(Lc_Exito OUT number)
as
begin
Lc_Exito := 123;
end;
/
Obviously this leaves out all the other parameters that were being sent in and the other "out" parameters - wanted to simplify it. But this shows how everything gets set up, from before, during, and after the call to the stored procedure in the C#, and how to set the OUT parameter, and get the value out, of the stored procedure.
With this
PROCEDURE "ADD_BOOKMARK_GROUP" (
"NAME" IN VARCHAR2,
"BOOKMARK_GROUP_ID" IN NUMBER,
"STAFF_ID" IN VARCHAR2,
"MAX_NO" IN INT,
"NUMFOUND" OUT INT,
"NEW_ID" OUT NUMBER) IS
BEGIN
NEW_ID := -1;
SELECT COUNT(*) INTO NUMFOUND FROM BOOKMARK_GROUP_TABLE WHERE STAFF_ID = STAFF_ID;
IF NUMFOUND < MAX_NO THEN
INSERT INTO BOOKMARK_GROUP_TABLE (NAME, BOOKMARK_GROUP_ID, STAFF_ID) VALUES(NAME, BOOKMARK_GROUP_ID, STAFF_ID);
SELECT BGT_SEQUENCE.currval INTO NEW_ID FROM dual;
END IF;
END;
I find it interesting that if I don't add parameters in the order they were defined in, e.g.
OracleCommand cmd = new OracleCommand("ADD_BOOKMARK_GROUP", conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(new OracleParameter("NAME", name));
...
cmd.Parameters.Add(new OracleParameter("NEW_ID", OracleDbType.Decimal)).Direction = ParameterDirection.Output;
cmd.Parameters.Add(new OracleParameter("NUMFOUND", OracleDbType.Int32)).Direction = ParameterDirection.Output;
instead of
OracleCommand cmd = new OracleCommand("ADD_BOOKMARK_GROUP", conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(new OracleParameter("NAME", name));
...
cmd.Parameters.Add(new OracleParameter("NUMFOUND", OracleDbType.Int32)).Direction = ParameterDirection.Output;
cmd.Parameters.Add(new OracleParameter("NEW_ID", OracleDbType.Decimal)).Direction = ParameterDirection.Output;
The values returned by
cmd.Parameters["NEW_ID"].Value.ToString()
and
cmd.Parameters["NUMFOUND"].Value.ToString()
get swapped, although running the procedure through the VS2008 Server Explorer returns correct data.
Why is this?
You can probably set the BindByName parameter on the OracleCommand object. This works for straight SQL queries with parameters, I've not tried it with stored procedures but it would be logical...
cmd.BindByName = true;
I'm not an Oracle buff, so I can't verify - but it sounds like they are being passed by position (rather than passed by name). The moral equivelent to:
EXEC SomeProc 'Foo', 'Bar'
instead of:
EXEC SomeProc #arg1='Foo', #arg2='Bar'
This isn't hugely uncommon - for years (in the COM days) a lot of my code had to work with a pass-by-position ADODB driver.
In this case, the name that you give serves only as a local key to lookup the value from the collection collection. You can verify easily by inventing a name:
cmd.Parameters.Add(new OracleParameter("BANANA", ...
cmd.Parameters.Add(new OracleParameter("GUITAR", ...
...
cmd.Parameters["BANANA"].Value.ToString()
cmd.Parameters["GUITAR"].Value.ToString()
If the above runs without error, it is passing by position. And it they are passed by position... then simply add them in the right order ;-p And never add new parameters except at the end...
Not an answer to the question but you can use 'insert ... returning ... into ' in stead of select bgt_sequence.currval from dual, for example:
begin
insert into test (id)
values(test_seq.nextval)
returning id into p_id;
end;
See http://www.adp-gmbh.ch/ora/sql/insert_into_x_returning_y.html