Passing tablename to a stored procedure c# - c#

I'm new to programming and I'm programming with Visual Studio. I'm trying to get an input from user (a name of a site like google.com) and search for the site name toward my tables (I have different domain tables such as .com , .org , etc).
So, I'm trying to write this stored procedure which selects from a table without actual table name (I'm trying to pass table name from input to stored procedure) here is my stored procedure:
CREATE PROCEDURE test
#link nvarchar(50)
AS
SELECT *
FROM #link
I have defined linksg (set and get) like this:
public string linksg
{
get { return link; }
set { link = value; }
}
and this is how I defined linksg in a function (my search_sitedomain function takes a domain like .com and gives a link to a table which includes your sitename like .com table):
public void search_sitedomain()
{
SqlConnection con = new SqlConnection("Data Source=SM;Initial Catalog=mohandesi-net;Integrated Security=True;Pooling=False");
SqlCommand cmd = new SqlCommand("search_sitedomain", con);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#domain", domain);
con.Open();
string link = Convert.ToString(cmd.ExecuteScalar());
linksg = link;
MessageBox.Show(link);
}
The search_sitedomain function works perfectly fine and returns the link but my stored procedure doesn't work like it can't replace #link with a tablename (like .com)
So what am I doing wrong?

In my opinion having a parametrized table name is a huge security hole, but it's possible to do it as follows:
CREATE PROCEDURE test
#link nvarchar(50)
AS
EXEC ('SELECT * FROM dbo.['+#link+']');

Related

Issue with Oracle stored procedure returning SYS_REFCURSOR and Entity Framework Model

I have an Oracle database (11.2 server-side with 12.1 client bits) with loads of stored procedures that return a SYS_REFCURSOR object type.
I tried to import this set of procedures through the Add new ADO.NET Entity Data Model wizard within Visual Studio 2017 (15.6.3) and the Oracle Managed DataAccess client (12.1).
But when I access these stored procedures I get an exception such as the following:
PLS-00306: wrong number or types of arguments in call to 'my_procedure'
An example of such an Oracle stored procedure looks like the following:
create or replace PROCEDURE my_procedure (
input IN VARCHAR2,
cur_output OUT SYS_REFCURSOR
)
IS
BEGIN
OPEN cur_output FOR
SELECT col1
, col2
, col3
FROM my_table
WHERE col1 = input;
EXCEPTION
WHEN NO_DATA_FOUND THEN
NULL;
WHEN OTHERS THEN
RAISE;
END my_procedure;
The generated model xml looks like:
<Function Name="my_procedure" Aggregate="false" BuiltIn="false" NiladicFunction="false" IsComposable="false" ParameterTypeSemantics="AllowImplicitConversion" Schema="myschema">
<Parameter Name="input" Type="varchar2" Mode="In" />
</Function>
Generated C# code looks like the following:
public virtual int my_procedure(string input) {
var inputParameter = input != null ?
new ObjectParameter("input", input) :
new ObjectParameter("input", typeof(string));
return ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction("my_procedure", inputParameter);
}
I played a bit with manually calling the Oracle DataAccess APIs and the following code works:
OracleConnection conn = new OracleConnection(...);
conn.Open();
using (OracleCommand cmd = new OracleCommand("my_procedure", conn)) {
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("input", OracleDbType.Varchar2).Value = "myinput";
cmd.Parameters.Add("cur_output", OracleDbType.RefCursor, null, ParameterDirection.Output);
var dr = cmd.ExecuteReader();
dr.Read();
var col1id = dr.GetOrdinal("col1");
var valuecol1 = SafeGetString(dr, col1id);
}
conn.Dispose();
Ideally I would like to have an automated process to generate the correct C# code to access the stored procedures. What is the most practical way to fix this?
You define your stored procedure as my_procedure with two arguments, input and cur_output. When you call this procedure in C#, you should also pass a parameter FOR BOTH input and cur_output. A procedure is not a function wherein it returns a value. Procedure will assign the output to the variable that you assigned as the OUT parameter, which is in this case named, cur_output.

SQL Server stored procedure doesn't return a result in VS C# but does in SQL Server

I have written a stored procedure that returns XML. When I run the stored procedure in SQL Server management studio, it returns the xml as it should but, when I run it in my C# code, no xml is returned. My code looks like this:
using (SqlConnection conn = new SqlConnection(connStr)) {
using (SqlCommand cmnd = new SqlCommand("dbo.spMyStoredProcXML", conn)) {
cmnd.CommandType = CommandType.StoredProcedure;
cmnd.Parameters.Add("#Param1", SqlDbType.VarChar, 50);
cmnd.Parameters["#Param1"].Value = "Some value";
//more parameters...
conn.Open();
XmlReader xrdr = cmnd.ExecuteXmlReader();
//do stuff...
}
}
I have checked the permissions for the user that I created, and they look like this:
At the server level, in the Login Properties dialog, under User Mapping, I have mapped the user to the correct database, and "checked" the public, db_datareader, db_datawriter, and then even added them to db_owner roles.
At the database level, I have also gone into the "Securables" section of the Database User dialog and explicitly given the user Grant and With Grant permissions to Execute the stored procedure in question. I have also explicitly selected "Grant" permissions for the user to Delete, Insert, Select, and Update all the tables in the database.
Still, when the "XmlReader xrdr = cmnd.ExecuteXmlReader();" line runs, the xrdr variable is empty. No error is reported. Can someone give suggestions as to what else I need to examine?
Thanks in advance for any help you can provide.
Here is a simplified version of the stored procedure (which works perfectly in SQL Server Management Studio):
CREATE PROCEDURE [dbo].[spGetXML]
(#param1 varchar(50), #param2 varchar(1))
AS
BEGIN
SET NOCOUNT ON;
with xmlnamespaces ('http://schemas.xmlsoap.org/soap/encoding/' as SOAP_ENC)
select
d.Col1,
d.Col2,
from MyTable d
where d.Col1 = #param1 and
d.Col2 = #param2
FOR XML PATH('ObjectName'), root('DOCUMENT'), type
END
I suppose your StoredProcedure has already the necessary fields.
So, try this:
using (SqlConnection conn = new SqlConnection(connStr)) {
conn.Open();
using (SqlCommand cmnd = new SqlCommand("dbo.spMyStoredProcXML", conn)) {
cmnd.CommandType = CommandType.StoredProcedure;
cmnd.Parameters.AddWithValue("#Param1", "Some value";)
//more parameters...
XmlReader xrdr = cmnd.ExecuteXmlReader();
//do stuff...
}
}
Maybe try this:
In your procedure make sure your parameter is defined as an output param:
CREATE PROCEDURE [dbo].[MyStoredProcedure]
#Param1 xml OUTPUT
SET #Param1 = (SELECT XML from TABLE)
Then in your C# code:
cm.Parameters.Add("#Param1", SqlDbType.Xml).Direction = ParameterDirection.Output;
Param1 = Convert.ToString(cm.Parameters["#Param1"].Value);
Obviously, adjust your datatypes to whatever is fitting. Additionally, if you're doing a bunch of work in this procedure I would personally use ExecuteNonQuery as opposed to using an XMLReader

Quote default values in create table SQL Server command

I want to write a C# method that creates a table and adds a column. The default values for the column is given as argument to the method. What is the safest way to quote the default value in the SQL command?
The code would be something like this:
var defaultValueThatOriginatesFromAnEvilSource = "'; DROP TABLE #Entities; SELECT '"; // the argument
database.RawExecute(string.Format("create table #Entities (somecolumn int default {0})", defaultValueThatOriginatesFromAnEvilSource));
Would a simple replace of the single quotes in the argument take care of all types of injection? Or is there a special method in C# or SQL I should use for this?
One thing to note, is that I create a temp table, and I need that to be accessible to the the next SQL statement (using the same connection).
As what shA.t said you can do this by sqlcommand in C# though it's quite hardwork if you'll be having multiple columns
but here's how to do it using stored procedure in SQL and sqlcommand in C#
in SQL
CREATE PROCEDURE sp_CreateTable
#TableName VARCHAR(50),
#ColumnName VARCHAR(50)
AS
BEGIN
DECLARE #SQLCreate VARCHAR(MAX)
SET #SQLCreate ='CREATE TABLE ' + #TableName
+ '('+#ColumnName+')'
EXEC (#SQLCreate)
END
GO
and in C#
add this using directives
using System.Data;
using System.Data.Client;
SqlConnection con = new SqlConnection("your connection string here");
con.Open();
SqlCommand cmd = new SqlCommand("sp_CreateTable");
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#TableName", SqlDbType.VarChar).Value = "someName";
cmd.Parameters.Add("#ColumnName", SqlDbType.VarChar).Value = "someColumnName";
cmd.ExecuteNonQuery();
con.Close();

MS-SQL Stored Procedure doesn't work with empty params

I have a form with inputs 'name' and 'phone'.
When they have values, everything works: a record is inserted into the database using a stored procedure, spFoo:
String sp = "spFoo 'test name','test phone'";
OdbcCommand command = new OdbcCommand(sp, connection);
command.CommandType = System.Data.CommandType.StoredProcedure;
connection.Open();
Response.Write(command.ExecuteNonQuery().ToString());
Works on application
Works on Mgmt Studio
But when they don't have values I get -1 as a response in the application:
String sp = "spFoo '',''";
Does not work in application (-1)
Works on Mgmt Studio
I want the user to be able to create a record without any input.
Why does this work in management studio, but not on the application?
Update: I added defaults to the params in the stored procedure, it didn't work; I gave empty strings "NULL" as values in the code, still no luck. Is this a server setting or something that won't allow empty variables?
You'll need to remove the SET NOCOUNT ON; from your stored procedure.
From the documentation:
Stops the message that shows the count of the number of rows affected by a Transact-SQL statement or stored procedure from being returned as part of the result set.
As others have pointed out you should parameterise your query too but the -1 is caused by NOCOUNT being ON.
Edit
I realise it's not what you're asking but to use a parameterised query with ODBC you need to use ?'s as ordinal place holders as per the documentation here. For example:
using (OdbcConnection connection = new OdbcConnection(connectionString))
{
string sp = "{call spFoo (?, ?)}";
using (OdbcCommand command = new OdbcCommand(sp, connection))
{
command.CommandType = System.Data.CommandType.StoredProcedure;
connection.Open();
//the order here is important, the names are not!
command.Parameters.Add("#name", OdbcType.VarChar).Value = "test name";
command.Parameters.Add("#phone", OdbcType.VarChar).Value = "test phone";
Console.WriteLine(command.ExecuteNonQuery().ToString());
}
}
When you are calling a stored procedure from code, you should use the Parameters property on the command. Try this:
String sp = "spFoo";
command.Parameters.Add("#name", "test name");
command.Parameters.Add("#phone", "test phone");
As JimmyV said, you should use the command.Parameters.Add method to setup your parameters, passing in null whenever a parameter value is not specified. To address your comment about the error 'procedure or function 'spFoo' expects parameter '#name', which was not supplied', you'll also need to modify your stored procedure to use default values when a param is not supplied (e.g. null):
CREATE PROCEDURE MyStoredProcedure
#foo int = null
AS
BEGIN
...
END
Sorry for not adding this a comment on the above post. Not enough reputation!
You shouldn't be calling a stored procedure the way that you currently are. You should be using parameters. Your code is susceptible to SQL injection.
Never string concat user inputted values.
What you should have, is a stored procedure setup similarly:
CREATE PROCEDURE spFoo
#name varchar(50) = 'Jim', -- default
#phone varchar(50) = null -- optional
AS
BEGIN
SET NOCOUNT ON;
-- INSERT STATEMENT
END
GO
And then supply the parameters in the code:
string name = this.nameTextBox.Text;
string phone = this.phoneTextBox.Text;
if (string.IsNullOrWhiteSpace(name))
name = null;
if (string.IsNullOrWhiteSpace(phone))
phone = null;
SqlConnection connection = new SqlConnection(#"<connection string>");
using (SqlCommand command = connection.CreateCommand())
{
command.CommandType = CommandType.StoredProcedure;
// leave this as the stored procedure name only
command.CommandText = "spFoo";
// if name is null, then Jim gets passed (see stored procedure definition)
// if phone is null, then null gets passed (see stored procedure definition)
command.Parameters.AddWithValue("#name", name);
command.Parameters.AddWithValue("#phone", phone);
try
{
connection.Open();
int result = command.ExecuteNonQuery();
Console.WriteLine(result);
}
finally
{
if (connection.State != ConnectionState.Closed)
connection.Close();
}
}
I'm not sure why you used the Odbc namespace objects since it sounds like you are using MS-SQL. You should be using objects from the System.Data.SqlClient namespace.
The answer to your actual question would most likely involve executing a script (not a stored procedure) similar to:
DECLARE #RC int
DECLARE #name varchar(50)
DECLARE #phone varchar(50)
-- TODO: Set parameter values here.
EXECUTE #RC = spFoo
#name,
#phone
GO
Which is not recommended.

Stored procedure calling, a weird situation i'm facing

Using Visual Studio 2008, C#
For the past 2 days I'm facing a problem so I thought I would ask here.
I have this stored procedure in my database called StoredProcedure1:
ALTER PROCEDURE dbo.StoredProcedure1
#ID int,
#Username varchar(10),
#Pass varchar(10),
#Status varchar(10)
AS
INSERT INTO tPasswords(ID, fUsername, fPassword, fStatus)
Values (#ID, #Username, #Pass, #Status)
RETURN
I am simply adding a row into my table.
When I execute the procedure from the server explorer inside visual studio everything runs smoothly, and when I see the data into my database I see the new row I just added.
The problem is when I'm trying to run the procedure inside my program.
So for test inside an empty form I created a button and :
using System.Data.Sql;
using System.Data.SqlClient;
private void button1_Click(object sender, EventArgs e)
{
string a = "Andreas";
string b = "Andreas2";
string c = "Andreas3";
int _id = 10;
SqlConnection connection = new SqlConnection(
Properties.Settings.Default.dPasswordsConnectionString);
SqlCommand cmd = new SqlCommand(
"StoredProcedure1", connection);
connection.Open();
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandTimeout = 600;
cmd.Parameters.Add("#ID", _id);
cmd.Parameters.Add("#Username", a);
cmd.Parameters.Add("#Pass", b);
cmd.Parameters.Add("#Status", c);
int i = cmd.ExecuteNonQuery();
connection.Close();
}
When I press this button I don't have any errors or anything, when I press it twice it causes an error about the same primary key, so the procedure is working.
But when I go to my database I don't see the new data been inserted.
That's my problem actually, I can't write to my database from within my program.
you are trying to set the primary key in your stored procedure, i am guessing.
you should let SQL set it for you.
I am guessing #ID is your primary key... remove that code, and the code from your proc where you are inserting the value into the row.
you should make sure your column definition is set to auto-generate these for you.

Categories