executing Oracle stored procedures using ADO (c#) - c#

Im trying to call a Oracle stored proc from a C# application using the following code
Connection conn = new Connection();
Recordset rs = new Recordset();
conn.Open("Provider=MSDAORA;User Id=username;Password=password;Data Source=DB;", null, null, 0); ;
rs.Open("sproc 'abc', 'xyz'", conn, ADODB.CursorTypeEnum.adOpenStatic, ADODB.LockTypeEnum.adLockReadOnly, -1);
where abc and xyz are input parameters..
However, I get "invalid SQL statement exception" when I try to run it..
Is there any other way to execute a oracle stored proc. I can execute MSSQL stored procs or normal Oracle queries in the same way described above..
I even tried using createparameter, but that didn't help either
Thanks,
Sam

Grab the Oracle ODP.NET tools: http://www.oracle.com/technology/software/tech/windows/odpnet/index.html
They are what I use to interact with our Oracle database from my ASP.NET application
Check here for an example of calling an Oracle stored procedure in C#.
Basically, with the package:
// Create oracle command object for the stored procedure
OracleCommand cmd = new OracleCommand("HR_DATA.GETCURSORS", conn);
cmd.CommandType = CommandType.StoredProcedure;
// Enter a parameter for the procedure
OracleParameter dep_id = new OracleParameter();
dep_id.OracleDbType = OracleDbType.Decimal;
dep_id.Direction = ParameterDirection.Input;
dep_id.Value = 60;
cmd.Parameters.Add(dep_id);
// Add more parameters ...
// Execute the stored procedure
Here's a link to the API documentation

Nevermind.. Apparently I was missing brackets around input parameters...
Thanks,
Sam

Related

How to Select an out parameter from a MySql Procedure in .net

Assume we have a stored procedure like so
CREATE PROCEDURE CopyValue(IN src INT, OUT dest INT)
BEGIN
SET dest = src;
END
I want to call this from a .net app (assume connection etc created successfully)
var sql = "call CopyValue(100, #destValue); select #destValue as Results;";
The string in the above statement works perfectly well when called in MySql Workbench.
However this - obviously - fails with "MySqlException: Parameter '#destValue' must be defined" when executed on a MySqlCommand object in .net
How do I arrange this statement so I can capture an output parameter from an existing procedure?
NB: I'm running against MySql 5.6, which I can't upgrade at this time.
NB Calling the procedure directly with CommandType.StoredProcedure goes against company guidelines.
By default, user-defined variables aren't allowed in SQL statements by MySQL Connector/NET. You can relax this restriction by adding AllowUserVariables=true; to your connection string. No modifications to your SQL or how you're executing the MySqlCommand should be necessary.
For information about why this is the default, you can read the research on this MySqlConnector issue (which also has the same default behaviour, but a much better error message that will tell you how to solve the problem): https://github.com/mysql-net/MySqlConnector/issues/194
A colleague (who wishes to remain anonymous) has answered this perfectly. Essentially put backticks ` after the # and at the end of the variable name e.g.
#`MyParam`
A fully working example.
static void Main(string[] args)
{
using var con = new MySql.Data.MySqlClient.MySqlConnection("Data Source=localhost; User Id=...;Password=...;Initial Catalog=...");
con.Open();
using var cmd = con.CreateCommand();
cmd.CommandText = "call CopyValue2(100, #`v2`); select #`v2` as Results;";
using var reader = cmd.ExecuteReader();
if (reader.Read())
Console.WriteLine($"Copied Value {reader.GetInt64(0)}");
}
Thanks OG :)

MySql.Data.MySqlClient Error when calling stored procedure

I am running into an issue, that I believe lies within my privileges granted. However, I can't figure out why this is happening. I have a stored procedure in MySQL defined by:
DELIMITER //
CREATE PROCEDURE my_stored_procedure (var_one VARCHAR(20), var_two INT4)
BEGIN
UPDATE table_name SET ACTIVATION_DATE = UTC_TIMESTAMP(),
DEACTIVATION_DATE = TIMESTAMPADD(MONTH, var_two, UTC_TIMESTAMP()),
USER_ACTIVATED = 1 WHERE ID = var_one;
END //
DELIMITER ;
I am calling this from my c# application. The code runs fine when I use userA's credentials. However, when I use userB it doesn't work. userA was granted privileges with the command:
GRANT ALL PRIVILEGES ON * . * TO 'userA'#'%';
userB was granted privileges with these commands:
GRANT UPDATE, SELECT ON current_db.table_im_updating TO 'userB'#'%';
GRANT EXECUTE ON PROCEDURE my_stored_procedure TO 'userB'#'%';
My code to call the mysql stored procedure is as follows:
connection = new MySql.Data.MySqlClient.MySqlConnection("server=ip_address; port=3306; database=data_base; UID=userA; password=password; pooling=false");
MySql.Data.MySqlClient.MySqlCommand command = new MySql.Data.MySqlClient.MySqlCommand();
command.Connection = connection;
command.CommandText = "my_stored_procedure";
command.CommandType = System.Data.CommandType.StoredProcedure;
command.Parameters.AddWithValue("#_id","associated_id");
command.Parameters["#_id"].Direction = System.Data.ParameterDirection.Input;
command.Parameters.AddWithValue("#subscription_length", "6");
command.Parameters["#subscription_length"].Direction = System.Data.ParameterDirection.Input;
command.ExecuteNonQuery();
Like I mentioned. This code works fine when userA and userA's password are entered; but when I switch to userB the error says,
System.Data.SqlTypes.SqlNullValueException: 'Data is Null. This method or property cannot be called on Null values.'
It is also worth noting that if I change my method of calling the procedure to this:
MySql.Data.MySqlClient.MySqlCommand command = new MySql.Data.MySqlClient.MySqlCommand("CALL my_stored_procedure(var_one, var_two)", connection);
I get no errors. I am not trying to just make my code work, I want it to work properly. Please help me understand what is causing this Error. Thanks.
TL;DR
userB should be granted with SELECT access to the mysql.proc table.
Explaination
First, MySQL Connnector/NET is executed SHOW CREATE PROCEDURE my_stored_procedure to get all parameters definition. (Order, Direction, DbType etc.)
Then, it will combine procedure name and parameters to create a sql like CALL my_stored_procedure(var_one, var_two) to execute.
To use SHOW CREATE PROCEDURE, you must be the user named in the routine DEFINER clause or have SELECT access to the mysql.proc table. If you do not have privileges for the routine itself, the value displayed for the Create Procedure field will be NULL.
-- Doc: SHOW CREATE PROCEDURE Syntax
-- Issue: Connector 8.0 - Stored Procedure Error in MySqlDataReader
Give the userB the privileges to Execute the SP and add CheckParameters=false to Connection String

SqlBulkCopy to temporary table in SqlServer 2008

i need to move a large amount of data to a sql server 2008 database. I get data from a source server and write using SqlBulkCopy to destination server. this data have to be parsed from a stored procedure and then deleted. I'd like to create a temporary data but, if i create the temp data on the client using SqlCommand the SqlBulkCopy can access the table and works fine, if i execute the same script on the server with a Stored Procedure the SqlBulkCopy.WriteToServer returns the InvalidOperationException "Cannot access destination table '#Tax'"
this is the code perfectly working:
SqlDataReader oSqlDataReader -> read form server source
SqlConnection oSqlConnection = new SqlConnection(_ConnectionTarget)
SqlCommand oSqlCommand = new SqlCommand("Create Table #Tax (Id int)", oSqlConnection);
oSqlCommand.CommandType = CommandType.Text;
oSqlCommand.CommandTimeout = 0;
oSqlCommand.ExecuteNonQuery();
SqlBulkCopy oSqlBulkCopy = new SqlBulkCopy(oSqlConnection)
oSqlBulkCopy.DestinationTableName = "#Tax";
oSqlBulkCopy.WriteToServer(oSqlDataReader);
this is the code throwing the InvalidOperationException exception:
SqlDataReader oSqlDataReader -> read form server a
SqlConnection oSqlConnection = new SqlConnection(_ConnectionTarget)
SqlCommand oSqlCommand = new SqlCommand("SP_CreateTax", oSqlConnection);
oSqlCommand.CommandType = CommandType.StoredProcedure;
oSqlCommand.CommandTimeout = 0;
oSqlCommand.ExecuteNonQuery();
SqlBulkCopy oSqlBulkCopy = new SqlBulkCopy(oSqlConnection)
oSqlBulkCopy.DestinationTableName = "#Tax";
oSqlBulkCopy.WriteToServer(oSqlDataReader);
SP_CreateTax:
Create Procedure SP_CreateTax
AS
Begin
Create Table #Tax (Id int)
End
The problem is that the temp table created in your stored procedure is only valid within the scope of that stored proc. Once it's done, the temp table is dropped.
Create the temp table the way you have (the way it works) via the inline sql and move on.
It seems that your stored procedure isn't executed and then your temporary table isn't created.
The reason is this:
SqlCommand oSqlCommand = new SqlCommand("SP_CreateTax", oSqlConnection);
Your stored procedure isn't executed, because to execute a procedure, you have to invoke: EXEC SP_CreateTax.
Note: It's not suggested to create stored procedures named with SP, because the names of reserved system stored procedures of SQL Server start with SP. For this reason, the names of custom stored procedures must be distinguished from the system ones, naming them, for example, as uSP_CreateTax.

SQL anywhere query error: Not enough values for host variables

I am building a query using ODBC command object in .Net with multiple parameters being passed in. When executing the query against SQL Anywhere, I get the following error. (The same code works against SQL Server).
[System.Data.Odbc.OdbcException] = {"ERROR [07002] [Sybase][ODBC Driver][SQL Anywhere]Not enough values for host variables"}
The command object has the same number of parameters added as the place holders ('?') in the query. Following is a simple query and C# code that fails the test.
C# code to populate the host variables
String queryText= #"DECLARE #loanuseraddress varchar(40), #loanid decimal
Set #loanid = ?
Set #loanuseraddress = ?
select * from loan_assignments where loan_id = #loanid"
OdbcConnection connection = new OdbcConnection(request.ConnectionString);
OdbcCommand command;
command = new OdbcCommand(queryText, connection);
OdbcParameter param1 = new OdbcParameter("#loanid", OdbcType.Decimal);
param1.Value = request.Loan.LoanNumber;
command.Parameters.Add(param1);
OdbcParameter param2 = new OdbcParameter("#loanuseremployer", dbcType.VarChar);
param2.Value = appraisalCompanyUpdate.LoanUserEmployer;
if (param2.Value == null)
param2.Value = DBNull.Value;
command.Parameters.Add(param2);
connection.Open();
OdbcDataReader rows = command.ExecuteReader();
I fixed this by checking for nulls. When you try to pass a null parameter to Sybase, that's the error you get (at least for me). Have a feeling LoanId is null at some point.
Edit After doing a little more research, I think you can also get this error when you try multiple insert / deletes / updates through the Sybase ODBC Connection in .Net. I don't think this is supported and MSDN seems to say it's vendor specific.
"Insufficient host variables" can also mean something else but it's applicable to the OP:
one of the other causes could be that you have a set of declared variables different from the set your SQL statement is using.
E.g. this could be a typo, or you could have copied in SQL from Visual Studio that was used to fill a dataset table using parameters (like :parm) but in doing so you forgot to declare it (as #parm) in your stored proc or begin/end block.

Call Oracle stored procedure from C#

I Have a stored procedure:
CREATE OR REPLACE PROCEDURE UpdateFileMapping(field in number, original_Field_Names in DBMS_SQL.varChar2_table, mapped_Field_Ids in DBMS_SQL.number_table)
IS
C NUMBER := DBMS_SQL.OPEN_CURSOR;
N NUMBER;
BEGIN
DBMS_SQL.PARSE(C,'INSERT INTO input_file_mapping VALUES(input_file_mapping_id.NextVal, 3, field, :fieldName, :mappedFieldId)', DBMS_SQL.NATIVE);
DBMS_SQL.BIND_ARRAY(C,':fieldName', original_Field_Names);
DBMS_SQL.BIND_ARRAY(C,':mappedFieldId', mapped_Field_Ids);
N := DBMS_SQL.EXECUTE(C);
DBMS_SQL.CLOSE_CURSOR(C);
END;
How to call such procedure which takes as input of DBMS_SQL.varChar2_table type from C#?
You need to include the proper ODP.NET provider for your system and then use OracleConnection and OracleCommand types to create a connection and execute the stored procedure. ODP.NET comes with extensive documentation and many examples.
Try:
void ExecOracleStoredProcedure(int field, string[] original_Field_Names, int[] mapped_Field_Ids)
{
using (OracleConnection connection = new OracleConnection(connectionString))
using (OracleCommand command = connection.CreateCommand())
{
command.CommandText = "UpdateFileMapping";
command.CommandType = CommandType.StoredProcedure;
command.Parameters.AddWithValue(":field").Value = field;
command.Parameters.AddWithValue(":original_Field_Names").Value = original_Field_Names;
command.Parameters.AddWithValue(":mapped_Field_Ids").Value = mapped_Field_Ids;
connection.Open();
command.ExecuteNonQuery();
}
}
Looks like Enterprise Library from MS still support Oracle Database
For the Data Access Application Block, the following is also required:
A database server running a database that is supported by a .NET Framework 3.5 with Service Pack 1 or .NET Framework 4.0 data provider. This includes SQL ServerĀ® 2000 or later, SQL Server 2005 Compact Edition, and Oracle 9i or later. The database server can also run a database that is supported by the .NET Framework 3.5 with Service Pack 1 or the .NET Framework 4.0 data providers for OLE DB or ODBC.
create or replace procedure UpdateFileMapping(m in Number,y in DBMS_SQL.varChar2_table,z in DBMS_SQL.number_table)
IS
C NUMBER;
N NUMBER;
BEGIN
C := DBMS_SQL.OPEN_CURSOR;
DBMS_SQL.PARSE(C,'INSERT INTO tablename VALUES(:x ,:fieldName,:mappedFieldId)',DBMS_SQL.NATIVE);
DBMS_SQL.BIND_ARRAY(C,':fieldName',original_Field_Names);
DBMS_SQL.BIND_ARRAY(C,':mappedFieldId',mapped_Field_Ids);
DBMS_SQL.BIND_VARIABLE(C,':x',file_Id);
N := DBMS_SQL.EXECUTE(C);
DBMS_SQL.CLOSE_CURSOR(C);
END;
For more information:
http://download.oracle.com/docs/cd/B28359_01/appdev.111/b28419/d_sql.htm

Categories