I am trying to use Npgsql to invoke a function (stored procedure) that takes a CHARACTER as parameter, but it doesn't work. If I declare the same function without parameters, or with an INTEGER parameter, I get the result sets that I want. When I declare the parameter as CHARACTER, it stops working. What is wrong?
Here is the code of my function:
CREATE OR REPLACE FUNCTION testrefcursor1(in xxx character varying(10)) RETURNS SETOF refcursor AS
$$
DECLARE
ref1 refcursor;
ref2 refcursor;
BEGIN
OPEN ref1 FOR
SELECT * FROM accounts;
RETURN NEXT ref1;
OPEN ref2 FOR
SELECT * FROM accounts;
RETURN NEXT ref2;
RETURN;
END;
$$
LANGUAGE plpgsql;
And here is the C# code that I am using:
var connection = new Npgsql.NpgsqlConnection(connectionString.ConnectionString);
connection.Open();
var trans = connection.BeginTransaction();
var command = new Npgsql.NpgsqlCommand("testrefcursor1", connection);
command.CommandType = System.Data.CommandType.StoredProcedure;
var parameter = command.CreateParameter();
parameter.ParameterName = "xxx";
parameter.DbType = System.Data.DbType.String;
parameter.Value = "10";
command.Parameters.Add(parameter);
var da = new Npgsql.NpgsqlDataAdapter(command);
var ds = new System.Data.DataSet();
da.Fill(ds);
trans.Commit();
connection.Close();
I already tried declaring the parameter as CHARACTER, CHARACTER(10), CHARACTER VARYING and CHARACTER VARYING(10)...
EDIT: I don't get any error message, but instead of getting the expected result set, I get an empty result set with a single column that has the same name as the function I am trying to call.
You're passing a Unicode argument to an ASCII parameter.
Change this line:
parameter.DbType = System.Data.DbType.String;
To:
parameter.DbType = System.Data.DbType.AnsiString;
Generally, Postgres's varchar columns are in Unicode, provided that the Unicode option on the database is enabled (see here). My guess is that it's not, and your parameter is unable to convert itself into the correct type to be passed through the function.
Which Npgsql version are you using?
Also, can you specify the parameter type using NpgsqlDbType? Sometimes the mapping isn't exactly and Npgsql can't find the function you are trying to use and can't make it work.
Npgsql tries to find an exact match of function name and parameter types. DbString matches text parameter types. Would you mind to give it a try and change your parameter type to text?
I hope it helps.
Not sure, if this has to do with your problem, but yesterday I stumbled across the fact that PostgreSQL has a "single-byte internal type" char that is different from the type char(1). Maybe there is some confusion about these?
I tried with the below approach (which is similar to yours):
using (NpgsqlConnection connection = new NpgsqlConnection(< connectionString >))
{
DataSet ds = new DataSet();
DataTable dt = new DataTable();
connection.Open();
NpgsqlCommand cmd = new NpgsqlCommand(< name of your SP >, connection);
cmd.CommandType = CommandType.StoredProcedure;
var param = cmd.CreateParameter();
param.ParameterName = < exact parameterName you used in your SP>;
param.DbType = System.Data.DbType.AnsiString;
param.Value = < parameter value >;
cmd.Parameters.Add(param);
NpgsqlDataAdapter adapter = new NpgsqlDataAdapter(cmd);
adapter.Fill(ds);
dt = ds.Tables[0];
}
This is working fine for me and I'm getting proper DataTable.
Related
I am using Npgsql ADO dot net connector to communicate to postgresql from C# code.
Function is available in the postgresql DB, also I am able to execute it from pgadmin tool but unable to call it from c# code.
getting error
42883: function
public.insert_json_array_to_test_method_temp(p_input_test_name =>
text, p_input_test_type_xref => text, p_input_unit_Attribute => text)
does not exist"}
error hint - No function matches the given name and argument types.
You might need to add explicit type casts.
Below is the C# code
NpgsqlConnection conn = new NpgsqlConnection(_connStr);
conn.Open();
NpgsqlCommand cmd = new NpgsqlCommand("public.insert_json_array_to_test_method_temp", conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(new NpgsqlParameter("p_input_test_name", NpgsqlDbType.Text) { Value = testmethod });
cmd.Parameters.Add(new NpgsqlParameter("p_input_test_type_xref", NpgsqlDbType.Text) { Value = testtypexref });
cmd.Parameters.Add(new NpgsqlParameter("p_input_unit_Attribute", NpgsqlDbType.Text) { Value = unitattributes });
NpgsqlDataReader dr = cmd.ExecuteReader();
while (dr.Read())
{
} conn.Close();
Below is the function header section
CREATE OR REPLACE FUNCTION
public.insert_json_array_to_test_method_temp(p_input_test_name
text,p_input_test_type_xref text,p_input_unit_attribute text)
RETURNS text
LANGUAGE 'plpgsql'
COST 100
VOLATILE
AS $BODY$
DECLARE res Text;
BEGIN
--some logic with parameters
res:= public."InsertTestNames"();
Return 'done';
END;
$BODY$;
Can any one please help what is the problem here ?
I changed the way I was creating the parameters and was casting it - it's now working.
var parameter1 = cmd.CreateParameter();
parameter1.ParameterName = "parameter_name";
parameter1.NpgsqlDbType = NpgsqlDbType.Text;
parameter1.Value = parameter_value;
cmd.Parameters.Add(parameter1);
I am a newbie in DB2 world and am using:
- DB2 Data Provider for .NET (IBM.Data.DB2.dll version 9.7.4.4)
- C# VS2010 with .NET Framework 4.0
I have problem with query that uses parameter.
My code snippet:
DB2Command cmd = new DB2Command();
cmd.CommandText = "SELECT COUNT(*) FROM CUSTOMERS t0 WHERE (t0.\"CITY\" < :p0)";
cmd.Connection = Db2Connection;
DB2Parameter param = cmd.CreateParameter();
param.DB2Type = DB2Type.VarChar;
param.ParameterName = ":p0";
param.Value = "Seattle";
var p = cmd.Parameters.Add(param);
var execResult = cmd.ExecuteScalar();
I get following error on cmd.ExecuteScalar():
The number of variables in the EXECUTE statement, the number of
variables in the OPEN statement, or the number of arguments in an OPEN
statement for a parameterized cursor is not equal to the number of
values required. SQLSTATE=07004
Please help how to fix the problem. Thank you in advance.
Additional information:
1. I just tried to use IBM Data Studio to verify the DB2 command using query editor. It doesn't recognize the prefix "#" for parameter. So I use oracle-liked prefix ":" for it. It works. But my C# code still raises the error [07004] SQL0313N
2. If I don't use any prefix for parameter on my C# code, I get ERROR [42703] [IBM][DB2/NT64] SQL0206N \"P0\" is not valid in this context.
Finally I find out 2 ways to fix the problem.
Using unnamed parameter "?" instead of parameter name ":p0".
DB2Command cmd = new DB2Command();
cmd.CommandText = "SELECT COUNT(*) FROM CUSTOMERS t0 WHERE (t0.\"CITY\" < ?)";
cmd.Connection = Db2Connection;
DB2Parameter param = cmd.CreateParameter();
param.DB2Type = DB2Type.VarChar;
param.ParameterName = "param1";
param.Value = "Seattle";
var p = cmd.Parameters.Add(param);
var execResult = cmd.ExecuteScalar();
Activate HostVarParameters property of class DB2ConnectionStringBuilder and the original code remains unchanged (keeping using named parameters).
My 2 cents,
Mag
I'm using output parameters to return values from a stored procedure.
Declaration in stored procedure is : #GrandTtl DECIMAL(19,3) OUT
The SELECT query is:
SET #GrandTtl = (SELECT TOP 1 Bill_Amount
FROM Tbl_Restaurant_Kitchen_Order_Bill_Details
WHERE Bill_Number = #billno)
For example, the select query returns the value 4087.67 then the output parameter value is returned as 4088 from SQL Server to C#.
Here is the C# code calling the stored procedure:
SqlCommand cmd = new SqlCommand("Sp_RestCC_BillDetails", con);
cmd.CommandType = CommandType.StoredProcedure;
SqlParameter OutParam26 = cmd.Parameters.Add("#GrandTtl", SqlDbType.Decimal,19);
da = new SqlDataAdapter(cmd);
con.Open();
da.Fill(ds, "dtRestCC_Items");
con.Close();
objRCCBEL.GrandTtlOut = Convert.ToDecimal(cmd.Parameters["#GrandTtl"].Value);
You need to set up the C# parameter as
output -- obviously you've done this
decimal type, with a correct/compatible scale
SqlParameter parm = new SqlParameter("#GrandTtl", SqlDbType.Decimal);
parm.Precision = 19;
parm.Scale = 3;
parm.Direction = ParameterDirection.Output;
cmd.Parameters.Add(parm);
If you do not set the scale, the default is 0. Ref: SqlParameter.Scale Property
The number of decimal places to which Value is resolved. The default is 0.
According to Microsoft decimal(p,s) should work for you. The money and smallmoneyt types are just a subset of decimal with precision of 4 places. So i think your problem comes from the type of the variable that is bound to the OUT parameter in C#.
I have a stored procedure that goes like this:
ALTER PROCEDURE [dbo].[AuthenticateUser]
#AzUserName varchar(20),
#Hash varchar(32),
#UserId bigint output,
#Authorized bit output
...
and runs just fine fine in Management Studio.
Here's my C# code:
SqlConnection scon = new SqlConnection(connectionString);
SqlCommand authCmd = new SqlCommand("AuthenticateUser", scon);
authCmd.CommandType = System.Data.CommandType.StoredProcedure;
SqlParameter userNameParam = authCmd.Parameters.Add("#AzUserName", System.Data.SqlDbType.VarChar, 20);
userNameParam.Value = username;
string hashed = Md5Hash.ComputeHash(username);
SqlParameter hashedParam = authCmd.Parameters.Add("#Hash", System.Data.SqlDbType.VarChar, 32);
hashedParam.Value = hashed;
SqlParameter userIdParam = authCmd.Parameters.Add("#UserId", System.Data.SqlDbType.Int);
userIdParam.Direction = System.Data.ParameterDirection.ReturnValue;
SqlParameter authorizedParam = authCmd.Parameters.Add("#Authorized", System.Data.SqlDbType.Bit);
authorizedParam.Direction = System.Data.ParameterDirection.ReturnValue;
scon.Open();
authCmd.ExecuteNonQuery();
scon.Close();
When I run it I am getting the following error:
{"Procedure or function 'AuthenticateUser' expects parameter '#UserId', which was not supplied."} System.Exception {System.Data.SqlClient.SqlException}
When I replace ParameterDirection.ReturnValue with ParameterDirection.Output I am not getting the error but never get the value of the procedure.
UPDATE:
Thank you All for your help. The error was more trivial than you would have thought and I described in the question. I have been changing back and forth ReturnValue to Output for quite a while today with no result. Then I had to post my question on SO just to realize that I am taking the hash value of ... username..Going outdoor to get some oxygen now.
You will have to use ParameterDirection.Output on every parameter, that has been marked with output in T-SQL. You can access the values, after the call to
authCmd.ExecuteNonQuery();
by getting the values of the parametes like this:
authCmd.Parametes["#UserId"].Value
You're confusing the concepts of OUTPUT and RETURN values.
A RETURN value from a stored procedure is a single integer value per stored procedure that is defined within your proc by using the RETURN statement eg
RETURN 1
A stored procedure can have zero to many parameters of which zero to many can be defined as OUTPUT.
In your case you're not showing any use of the RETURN statement but you are using OUTPUT parameters. In SQL Server these are more like input/output parameters and you need to provide a value.
You can access the resulting value of an OUTPUT parameter by looking at the parameters collection after calling the stored procedure and look at the value eg
authCmd.Parameters[2].Value
Or
userIdParam.Value
As per other answers, you need to use the output parameter direction to achieve this
You can access the values of authorizedParam.Value and userIdParam.Value after executing the command.
SqlConnection scon = new SqlConnection(connectionString);
SqlCommand authCmd = new SqlCommand("AuthenticateUser", scon);
authCmd.CommandType = System.Data.CommandType.StoredProcedure;
SqlParameter userNameParam = authCmd.Parameters.Add("#AzUserName", System.Data.SqlDbType.VarChar, 20);
userNameParam.Value = username;
string hashed = Zonal.Pie.Core.Common.Utils.Md5Hash.ComputeHash(username);
SqlParameter hashedParam = authCmd.Parameters.Add("#Hash", System.Data.SqlDbType.VarChar, 32);
hashedParam.Value = hashed;
SqlParameter userIdParam = authCmd.Parameters.Add("#UserId", System.Data.SqlDbType.Int);
userIdParam.Direction = System.Data.ParameterDirection.Output;
SqlParameter authorizedParam = authCmd.Parameters.Add("#Authorized", System.Data.SqlDbType.Bit);
authorizedParam.Direction = System.Data.ParameterDirection.Output;
scon.Open();
authCmd.ExecuteNonQuery();
//Access authorizedParam.Value and userIdParam.Value here
scon.Close();
I have the following parameter for SqlCommand. How do I make it to both in and out the paramter value for the Stored Procedure.
SqlCommand mySqlCommand = new SqlCommand("aspInsertZipCode", mySqlConnection);
mySqlCommand.CommandType = CommandType.StoredProcedure;
mySqlCommand.Parameters.Add("#DataRows", dataStringToProcess.ToString());
var pInOut = mySqlCommand.Parameters.Add("#DataRows", dataStringToProcess.ToString());
pInOut.Direction = ParameterDirection.InputOutput;
And then to read the output value after you've executed the command:
// assumes that the parameter is a string and that it could possibly be null
string value = Convert.IsDBNull(pInOut.Value) ? null : (string)pInOut.Value;
SqlParameter has a Direction enumeration. Set this value.
Then use the SqlCommand.Parameters.Add that takes a SqlParameter.
Parameter direction:
http://msdn.microsoft.com/en-us/library/system.data.parameterdirection.aspx
You then pull the value out after having called ExecuteNonQuery (for example), by getting the Value from the parameter out of the command collection:
myCommand.Parameters["#paramName"].Value
Can't remember, but I think there is a string indexer on that.
Alternatively, there is this one liner:
myCommand.Parameters.AddWithValue("#paramName", value).Direction = ParameterDirection.InputOutput;
One of the attributes of a SQL Command Parameter is the Direction. You would want to use (going off of memory)
SqlCommand mySqlCommand = new SqlCommand("aspInsertZipCode", mySqlConnection);
mySqlCommand.CommandType = CommandType.StoredProcedure;
mySqlCommand.Parameters.Add("#DataRows", dataStringToProcess.ToString());
mySqlCommand.Parameters("#DataRows").Direction = ParameterDirection.InputOutput;
SqlParameter DataRows = new SqlParameter("#DataRows", SqlDbType.Text)
{ Value = dataStringToProcess.ToString(), Direction = ParameterDirection.InputOutput};
mySqlCommand.Parameters.Add(DataRows);