I am passing the parameter like in C# page,
conn.Open();
MySqlCommand cmd = new MySqlCommand(sql, conn);
cmd.CommandText = commandtype.storedprocedure;
cmd.Parameters.AddWithValue("?user", user)
cmd.Parameters.AddWithValue("?name", name);
On the mysql stored procedures used 2 parameter for record exists finds
#id integer,
#name varchar(200)
BEGIN
IF EXISTS (SELECT * FROM usertable WHERE id = #id and mode =0 limit 1 )
THEN
UPDATE usertable SET name = name where id=#id and mode = 0;
ELSE
INSERT INTO usertable (name, mode)VALUES (#name`enter code here`,0);
END IF;
END
Another way of sending variables to a stored proc that I've used with no problem:
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#name", SqlDbTpye.Varchar).Value = name;
I think you can specify variable by size and type like this:
SqlDbTpye.Varchar,200
But not able to test that right now.
You need to make sure the prefixes for the parameters match. If you use "#" in your stored procedure, you need to use "#" in C#, too, not "?".
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#user", user)
cmd.Parameters.AddWithValue("#name", name);
Related
I read a lot about SQL injections lately and I know a SqlParameter will not prevent injections for sure, but is a table parameter as safe as a single parameter?
Some untested uncompiled example code for clarification:
Is this...
SQL:
CREATE PROCEDURE dbo.InsertSingle
#Name nvarchar(max),
#Phone nvarchar(max)
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO FooBar.dbo.SomeTable
VALUES(#Name, #Phone)
END
GO
C#:
foreach(User u in Users)
{
Connection.Open();
SqlCommand com = Connection.CreateCommand();
com.CommandType = CommandType.StoredProcedure;
com.CommandText = "dbo.InsertSingle";
SqlParameter p = new SqlParameter("#Name", u.Name);
com.Parameters.Add(p);
p = new SqlParameter("#Phone", u.Phone);
com.Parameters.Add(p);
com.ExecuteScalar();
}
as safe as this?
SQL:
CREATE PROCEDURE dbo.InsertBunch
#ValuesAsTable dbo.ValuesAsTableType READONLY
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO FooBar.dbo.SomeTable
SELECT *
FROM #ValuesAsTable
END
GO
C#:
DataTable valuesAsTable = Users.GetSomeInsertData();
Connection.Open();
SqlCommand com = Connection.CreateCommand();
com.CommandType = CommandType.StoredProcedure;
com.CommandText = "dbo.InsertBunch";
SqlParameter p = new SqlParameter("#valuesAsTable", valuesAdTable);
p.SqlDbType = SqlDbType.Structured;
p.TypeName = "dbo.ValuesAsTableType";
com.Parameters.Add(p);
com.ExecuteScalar();
I really tried to search it, but I cannot find good input. Can anyone link me in the right direction?
Thanks in advance
Typed parameters will prevent SQL injection if there is no possibility that they get interpreted as literal commands, and executed. Whether they are transported as scalar or table-valued parameters, does not make any difference in this regard.
I have a table called 'MatchType' and it contains:
ID | MatchTypeName
1 | One Day
2 | Two Day
3 | T20
I have a method to retrieve a record from that table based on a sting that will match a value in MatchTypeName:
public static int GetByName(string matchType)
{
MatchType item = new MatchType();
using (SqlConnection con = new SqlConnection(BaseDataAccessLayer.GetConnectionStringByName()))
{
using (SqlCommand cmd = new SqlCommand(STORED_PROC_GetByName, con))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#matchTypeName", SqlDbType.VarChar, 20).Value = matchType;
con.Open();
using (IDataReader reader = cmd.ExecuteReader())
{
item.LoadFromReader(reader);
}
}
}
return item.Id;
}
This method calls this stored procedure:
CREATE PROCEDURE [dbo].[MatchType_GetByName]
(#matchTypeName varchar(20))
AS
BEGIN
SET NOCOUNT ON
SELECT
[Id], [MatchTypeName]
FROM
[dbo].[MatchType]
WHERE
[MatchTypeName] = #matchTypeName
RETURN ##ERROR
END
When calling the GetByName method I am passing in a string "One Day". I have confirmed this through debugging. I can't post an error message that is helpful as there isn't one being generated. Just no data is being returned in the reader...
I have a couple of other methods and stored procedures that use a similar process and they work. The only thing that I can see is the difference is that I am using the WHERE clause on a varchar/string value which is something that the other queries don't do...
Yet i can run this stored proc and it returns all the records..
BEGIN
SET NOCOUNT ON
SELECT
[Id],
[MatchTypeName]
FROM
[dbo].[MatchType]
RETURN ##ERROR
END
The default length for varchar declared without size is 1. You declared it like that in your stored proc parameter so you're only passing the first character.
Change your declaration:
(#matchTypeName varchar)
to a relevant size:
(#matchTypeName varchar(20))
Also, add the size in the code and make sure that the case in your parameter name matches your stored proc:
cmd.Parameters.Add("#matchTypeName", SqlDbType.VarChar, 20).Value = matchType;
The procedure is running the query and showing the results (which is why it works in SSMS), but doesn't actually return anything. Try this (note, I haven't actually tested it).
CREATE PROCEDURE [dbo].[MatchType_GetByName]
#matchTypeName varchar(20),
#matchTypeID INT OUTPUT
AS
BEGIN
SET NOCOUNT ON
SELECT
#matchTypeID = [Id], [MatchTypeName]
FROM
[dbo].[MatchType]
WHERE
[MatchTypeName] = #matchTypeName
RETURN ##ERROR
END
Try this:
using (SqlCommand cmd = new SqlCommand(STORED_PROC_GetByName, con))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#matchTypeName", matchType);
con.Open();
using (IDataReader reader = cmd.ExecuteReader())
{
item.LoadFromReader(reader);
}
}
SqlCommand.Parameters Property
I am inserting into a database using a stored procedure and i am getting the error:
Procedure or function 'sp_Addrecord' expects parameter '#RecordNumber', which was not supplied.
RecordNumber is an auto incrementing ID so i understand id have to omit it from my insert command and specify which columns and where i have to insert to avoid this but i am calling the procedure which is handled by another class so where would i be able to specify this as you would normally say something like this:
SqlCommand cmd = new SqlCommand("INSERT INTO CARS (carDate, carTime) Values (#Date, #Time)", conDatabase);
Here is my code, i avoided the using statement for simplicity of this example:
List<CarRecord> carRecords;
private void Save_Record_Click(object sender, RoutedEventArgs e)
{
SqlConnection conDatabase = new SqlConnection(String.Format(#"Data Source={0};Initial Catalog={1};Persist Security Info=True;User ID={2};Password={3}", SQLFunctions.connectSQL.SQLSERVER_ID, SQLFunctions.connectSQL.SQLDatabaseName, SQLFunctions.connectSQL.SQLServerLoginName, SQLFunctions.connectSQL.SQLServerPassword));
conDatabase.Open();
SqlCommand cmd = new SqlCommand("sp_Addrecord", conDatabase);
cmd.CommandType = CommandType.StoredProcedure;
cmd.ExecuteNonQuery();
conDatabase.Close();
}
public bool Addrecord(CarRecord DataRecord)
{
return ExecuteNonQuery("sp_Addrecord", null,
CreateParameter("#Date", SqlDbType.NVarChar, DataRecord.carDate),
CreateParameter("#Time", SqlDbType.NVarChar, DataRecord.carTime),
);
}
EDIT - Stored Procedure:
USE [SDC Logging]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[sp_Addrecord]
#RecordNumber int,
#Date nvarchar(50),
#Time nvarchar(50),
AS
BEGIN
SET NOCOUNT ON;
WITH [source](RecordNumber, Date, Time)
AS
(
SELECT #RecordNumber, #Date, #Time,
)
MERGE dbo.Bags AS [target] USING [source]
ON [target].Date = [source].Date
WHEN MATCHED THEN UPDATE SET
[target].Date = #Date,
[target].Time = #Time,
WHEN NOT MATCHED THEN
INSERT ( Date, Time, )
VALUES( #Date, #Time, );
SELECT SCOPE_IDENTITY()
END
The error says it all. Your sp_Addrecord has a parameter specified that you are supplying. Basically, the parameters you specify here...
return ExecuteNonQuery("sp_Addrecord", null,
CreateParameter("#Date", SqlDbType.NVarChar, DataRecord.carDate),
CreateParameter("#Time", SqlDbType.NVarChar, DataRecord.carTime),
);
must match the name and datatype of the parameters defined by sp_Addrecord stored procedure. In addition, make sure your stored procedure's query matches this query...
INSERT INTO CARS (carDate, carTime) Values (#Date, #Time)
Edit based on your Edit
You need to specified the #RecordNumber parameter here...
return ExecuteNonQuery("sp_Addrecord", null,
CreateParameter("#RecordNumber", SqlDbType.Int, DataRecord.recordNumber),
CreateParameter("#Date", SqlDbType.NVarChar, DataRecord.carDate),
CreateParameter("#Time", SqlDbType.NVarChar, DataRecord.carTime),
);
Don't worry about the insert just make sure that when inserting you pass a "invalid record number" such as -1, if the MERGE statement doesn't find the record with id of -1 it will successfully insert the record with an auto-generated Id with the help of your identity column
Try This.
You don't need to call separate method Addrecord.
However, you still want to use a separate method. Add code below in the AddRecord method and remove existing code:
SqlParameter []parms = new SqlParameter[1];
parms[0] = new SqlParameter("#Date",DataRecord.carDate) ;
parms[1] = new SqlParameter("#Time",DataRecord.carTime) ;
cmd.Parameters.AddRange(parms);
cmd.CommandType = CommandType.StoredProcedure;
cmd.ExecuteNonQuery();
conDatabase.Close();
Hi all I have the following stored procedure
#UserName varchar(150),
#UserEmail varchar(300),
#UserPassword varchar(150),
#ContactNumber varchar(150),
#ContactMobile varchar(150),
#AreaOfCountry varchar(150),
#UserId int OUTPUT,
#AllreadyReg int OUTPUT
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
--DECLARE #UserId int, #AllreadyReg int
IF (SELECT COUNT(UserId) FROM Users WHERE (UserName = #UserName) OR (UserEmail = #UserEmail)) > 0
BEGIN
SET #UserId = 0
SET #AllreadyReg = 1
END
ELSE
BEGIN
INSERT INTO Users (UserName,UserEmail,UserPassword,ContactNumber,ContactMobile,AreaOfCountry) VALUES (#UserName,#UserEmail,#UserPassword,#ContactNumber,#ContactMobile,#AreaOfCountry)
SELECT #UserId = SCOPE_IDENTITY()
SET #AllreadyReg = 0
END
however when I use it using c# and asp.net its not returning anything, however when I just execute it it does have a results #UserId and #AllreadyReg but the return value is 0 and a single field.
my c# code is below but it never has any rows
using (SqlConnection con = new SqlConnection(connectionString))
{
Response.Write("Line 61");
using (SqlCommand cmd = new SqlCommand("spR_Register", con))
{
Response.Write("line 64");
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#UserName", TxtUsername.Text.Trim());
cmd.Parameters.AddWithValue("#UserEmail", TxtEmail.Text.Trim());
cmd.Parameters.AddWithValue("#UserPassword", TxtPassword.Text.Trim());
cmd.Parameters.AddWithValue("#ContactNumber", TxtPhone.Text);
cmd.Parameters.AddWithValue("#ContactMobile", TxtMobile.Text);
cmd.Parameters.AddWithValue("#AreaOfCountry", TxtAreaOfCountry.SelectedValue);
cmd.Parameters.AddWithValue("#UserId", ParameterDirection.Output);
cmd.Parameters.AddWithValue("#AllreadyReg", ParameterDirection.Output);
con.Open();
SqlDataReader reader = cmd.ExecuteReader();
if (reader.HasRows)
{
Response.Write("line 78");
etc etc
can anyone help
thanks
With the edit: the mistake is using ExecuteReader on a command that doesn't select a data grid - that should be done with ExecuteNonQuery.
The important thing here is how the parameter is added. For example:
var alreadyReg = cmd.CreateParameter();
alreadyReg.Direction = System.Data.ParameterDirection.Output;
alreadyReg.ParameterName = "AllreadyReg";
alreadyReg.DbType = DbType.Int32;
cmd.Parameters.Add(alreadyReg);
//...
cmd.ExecuteNonQuery();
//...
int val = (int)alreadyReg.Value;
Depending on the type of DbCommand object, there may be an overload that accepts all of these in one line - the above assumes just DbCommand. With SqlCommand, you can simplify a bit:
var alreadyReg = cmd.Parameters.Add("AllreadyReg", SqlDbType.Int);
alreadyReg.Direction = ParameterDirection.Output;
//...
cmd.ExecuteNonQuery();
//...
int val = (int)alreadyReg.Value
You might have already handled it, but just in case, make sure to specify direction of parameter in c# code.
Here
cmd.Parameters.AddWithValue("#UserId", ParameterDirection.Output);
wrong usage of AddWithValue. The second parameter is parsed as parameter value, not direction type. Use proper parameter contructor and the add the result to collection.
I'm trying to execute a stored procedure (against SQL Server 2005 through the ODBC driver) and I recieve the following error:
Procedure or Function 'GetNodeID' expects parameter '#ID', which was not supplied.
#ID is the OUTPUT parameter for my procedure, there is an input #machine which is specified and is set to null in the stored procedure:
ALTER PROCEDURE [dbo].[GetNodeID]
#machine nvarchar(32) = null,
#ID int OUTPUT
AS
BEGIN
SET NOCOUNT ON;
IF EXISTS(SELECT * FROM Nodes WHERE NodeName=#machine)
BEGIN
SELECT #ID = (SELECT NodeID FROM Nodes WHERE NodeName=#machine)
END
ELSE
BEGIN
INSERT INTO Nodes (NodeName) VALUES (#machine)
SELECT #ID = (SELECT NodeID FROM Nodes WHERE NodeName=#machine)
END
END
The following is the code I'm using to set the parameters and call the procedure:
OdbcCommand Cmd = new OdbcCommand("GetNodeID", _Connection);
Cmd.CommandType = CommandType.StoredProcedure;
Cmd.Parameters.Add("#machine", OdbcType.NVarChar);
Cmd.Parameters["#machine"].Value = Environment.MachineName.ToLower();
Cmd.Parameters.Add("#ID", OdbcType.Int);
Cmd.Parameters["#ID"].Direction = ParameterDirection.Output;
Cmd.ExecuteNonQuery();
_NodeID = (int)Cmd.Parameters["#Count"].Value;
I've also tried using Cmd.ExecuteScalar with no success. If I break before I execute the command, I can see that #machine has a value.
If I execute the procedure directly from Management Studio, it works correctly.
Any thoughts? Thanks
Try replacing :
OdbcCommand Cmd = new OdbcCommand("GetNodeID", _Connection);
Cmd.CommandType = CommandType.StoredProcedure;
With :
OdbcCommand Cmd = new OdbcCommand("{call GetNodeID(?,?)}", _Connection);
More info :
http://support.microsoft.com/kb/310130
I'm not exactly sure what you mean by
there is an input #machine which is
specified and is set to null in the
stored procedure
In your proc's signature, this line:
#machine nvarchar(32) = null
doesn't mean that you're setting #machine to null inside the proc - it means you're assigning a default value to be used in case the parameter is missing (in this case, null is the value to be used for a missing param).
Getting the error about #ID being missing would happen if you were calling this stored procedure without passing any parameters at all (#machine would not be flagged as a problem since it has a default value defined). Your code example looks fine to me - are you sure the stored proc isn't being called from somewhere else in your program (somewhere where no parameters are being added)?
Stored procedure with input parameters and ODBC Connection:
create a stored procedure:
create procedure proc_name #parm1 varchar(20), #parm2 varchar(10) as begin insert into table_name values(#parm1,#parm2);end
This code works in SQL Server.
private void button1_Click(object sender, EventArgs e)
{
string name = txtname.Text;
string num = txtnum.Text;
OdbcConnection con = new OdbcConnection("dsn=naveenk_m5");
OdbcCommand cmd = new OdbcCommand("{call proc1(?,?)}",con);
cmd.Parameters.Add("#parm1", OdbcType.VarChar).Value=name;
cmd.Parameters.Add("#parm2", OdbcType.VarChar).Value = num;
con.Open();
cmd.ExecuteNonQuery();
con.Close();
MessageBox.Show("inserted a row");
}