Using Parameter in Sql Query [duplicate] - c#

I got a runtime error saying "Must declare the table variable "#parmTableName". Meaning having table name as sql parameter in the sql-statement is not allowed.
Is there a better option or suggestion than allowing sql injection attack? I don't want to do this C# script for sql statement " DELETE FROM " + tableName + " ";
using(var dbCommand = dbConnection.CreateCommand())
{
sqlAsk = "";
sqlAsk += " DELETE FROM #parmTableName ";
sqlAsk += " WHERE ImportedFlag = 'F' ";
dbCommand.Parameters.Clear();
dbCommand.Parameters.AddWithValue("#parmTableName", tableName);
dbConnection.Open();
rowAffected = dbCommand.ExecuteNonQuery();
}

Go for a white list. There can only be a fixed set of possible correct values for the table name anyway - at least, so I'd hope.
If you don't have a white list of table names, you could start with a whitelist of characters - if you restrict it to A-Z, a-z and 0-9 (no punctuation at all) then that should remove a lot of the concern. (Of course that means you don't support tables with odd names... we don't really know your requirements here.)
But no, you can't use parameters for either table or column names - only values. That's typically the case in databases; I don't remember seeing one which did support parameters for that. (I dare say there are some, of course...)

As others have already pointed out that you can't use Table Name and Fields in Sql Parameter, one thing that you can try is to escape table name using SqlCommandBuilder, like:
string tableName = "YourTableName";
var builder = new SqlCommandBuilder();
string escapedTableName = builder.QuoteIdentifier(tableName);
using (var dbCommand = dbConnection.CreateCommand())
{
sqlAsk = "";
sqlAsk += " DELETE FROM " + escapedTableName; //concatenate here
sqlAsk += " WHERE ImportedFlag = 'F' ";
dbCommand.Parameters.Clear();
dbConnection.Open();
rowAffected = dbCommand.ExecuteNonQuery();
}

(sqlAsk is string, right?) if it's right so let's try this:
using(var dbCommand = dbConnection.CreateCommand())
{
sqlAsk = "";
sqlAsk += " DELETE FROM <table_name> ";
sqlAsk += " WHERE ImportedFlag = 'F' ";
string table_name = "Your table name here"; //<- fill this as u need
sqlAsk = sqlAsk.Replace("<table_name>", table_name); // it will replace <table_name> text to string table_name
dbConnection.Open();
rowAffected = dbCommand.ExecuteNonQuery();
}

Related

Can a C# SQL Parameter Contain '='

So I am trying to create parameters to pass to my query and was wondering if I could pass a parameter that contains an '=' sign in it that replaces the traditional '=' sign in the SQL statement. It would be like the following:
string aoi = "=" + comboBox1.Text;
string comp = "=" + comboBox2.Text;
//Default values of their respective Combo Boxes.
if(aoi == "Area Of Interest")
aoi = "!= NULL";
if (comp == "Company")
comp = "!= NULL";
cmd.CommandText = "SELECT * FROM JobListInfo" +
"WHERE AreaOfInterest #AOI AND Company #Company";
cmd.Parameters.AddWithValue("#AOI", aoi);
cmd.Parameters.AddWithValue("#Company", comp);
The reason I am asking is because if the user doesn't change the default value, I want it to pull all the records (with respect to the rest of the SQL statement). I understand I could create an OR statement, but I have three other parameters I would like to pass as well and didn't want to create 15 OR cases.
EDIT: I found a solution to my problem. I changed the '=' to Like and changed the strings to '%' if they didn't select a value. This shouldn't cause any SQL injection issues, right?
Sample Code:
if(aoi == "Area of Interest")
aoi = "%"
cmd.CommandText = "SELECT * FROM JobListInfo " +
"WHERE AreaOfInterest LIKE #AOI";
cmd.Parameters.AddWithValue("#AOI", aoi);
Not via a parameter. If this were allowed, it would potentially introduce SQL injection vulnerabilities.
A potential solution would be to dynamically create the CommandText string by appending database column names and parameter placeholders to the query's WHERE clause.
WARNING: Do not append input values to the WHERE clause of your query string! This will leave you vulnerable to SQL injection. Instead, append parameter placeholders and then populate them using the cmd.Parameters.AddWithValue() method.
That being said, something like the code below might work. However, it would depend on you selecting a single default value for your combo-boxes. Consequently, you would need to use UI labels instead of default values to describe the combo-boxes in your app.
string MY_DEFAULT_VALUE = 'Pick One:';
string queryString = "SELECT * FROM my_table";
//Populate Dictionary:
Dictionary<string,ComboBox > columnDictionary= new Dictionary<string, ComboBox>();
columnDictionary.Add("COL_A", comboBox1);
columnDictionary.Add("COL_B", comboBox2);
columnDictionary.Add("COL_C", comboBox3);
//etc...
List<KeyValuePair<string, ComboBox>> appendedColumns = new List<KeyValuePair<string, ComboBox>>();
foreach (KeyValuePair<string, ComboBox> entry in columnDictionary)
{
if (!String.Equals(entry.Value.Text, MY_DEFAULT_VALUE, StringComparison.OrdinalIgnoreCase))
{
string currentColumnName = entry.Key;
string currentColumnParameter = "#" + entry.Key;
if (appendedColumns.Count>1)
{
queryString += " AND ";
}
else
{
queryString += " WHERE ";
}
queryString += currentColumnName + " = " + currentColumnParameter;
appendedColumns.Add(entry);
}
}
cmd.CommandText = queryString;
if (appendedColumns.Count > 0)
{
foreach (KeyValuePair<string, ComboBox> entry in appendedColumns)
{
string currentColumnParameter = "#" + entry.Key;
string currentParameterValue = entry.Value.Text;
cmd.Parameters.AddWithValue(currentColumnParameter, currentParameterValue);
}
}
//Continue on your way...
Short answer to your question is, you cannot use '=' as you have shown. So change your code like this;
string aoi = comboBox1.Text;
string comp = comboBox2.Text;
string sql;
if (aoi == "Area Of Interest" && comp == "Company")
{
sql = #"SELECT * FROM JobListInfo WHERE AreaOfInterest Is Not NULL AND Company Is Not NULL";
}
else if(....)
{
sql =............................
}
else
{
sql = #"SELECT * FROM JobListIn WHERE AreaOfInterest = #AOI AND Company = #Company";
}
cmd.CommandText = sql;
cmd.Parameters.AddWithValue("#AOI", aoi);
cmd.Parameters.AddWithValue("#Company", comp);

C#: Find tables involved in SQL query

Given a SQL query variable, i.e.,
string mySQLQuery = "SELECT TableA.Field1, TableA.Field2,..., TableB.Field1, TableB.Field2,.... FROM TableA LEFT OUTER JOIN TableB ON TableA.Field1 = TableB.Field1"
Is there any straight way I can extract the fields and the table names within the query in two lists? so:
List "Fields":
All fields From table A, table B (and others I could add by joining) with their table prefix (even if there were only one table in a simple 'SELECT * FROM TableA', I'd still need the 'TableA.' prefix).
All fields From table B with their table prefix, by adding them to the list in the usual fieldList.Add() way through looping.
List "Tables":
All tables involved in the query in the usual tablesList.Add() way through looping.
My first approach would be to make a lot of substrings and comparisons, i.e., finding the FROM, then trimming left, the substring until the first blank space, then the JOIN, then trimming, then the first substring until the space..., but that doesn't seem the right way.
REEDIT
I know I can get all the fields from INFORMATION_SCHEMA.COLUMNS with all the properties (that comes later), but the problem is that for that query I need the tables to be known. My steps should be:
The query "SELECT [fields] FROM [tables]" comes from a Multiline Textbox so I can write a SQL Query to fetch the fields I'd like. I take the string by txtMyQuery.Text property.
Find the field in the SELECT query, and find what table belongs to in the FROM clause.
Store the field like [Table].[Field]in a string list List strFields = new List() by the strFields.Add() method;
Then, iterate through the list in a way like:
for (int i = 0; i < fieldList.Count; i++)
{
string mySqlQuery = "SELECT Table_Name, Column_Name, Data_Type FROM INFORMATION_SCHEMA.COLUMNS
WHERE (COLUMN_NAME + "." + TABLE_NAME) ='" + fieldList[i] + "'";
//Commit query, get results in a gridview, etc.
}
Sure,
Tables:
SELECT TABLE_NAME FROM information_schema.TABLES
Fields:
SELECT * FROM information_schema.COLUMNS WHERE TABLE_NAME = N'Your Table'
Ok, after a while, I found SOME way to make this happen... I will work this out as I improve the solution (i.e., now it doesn't work if we use * selections like 'SELECT * FROM TableA', doesn't support aliasing, and all fields in the SELECT should be [table].[field], but will give an idea of what I'm trying to achieve):
This way, I write an SQL statement in a textbox, I pass it onto a new form to check the actual results of the query (if I needed, by clicking on a button "Preview"), and I populate a datagridview with the SCHEMA data I wanted to retrieve.
Thanks to all for your support!
private void btnQuery_Click(object sender, EventArgs e)
{
string strSql = this.txtQuery.Text;
DataTable dt = new DataTable();
String conStr = "Data Source=(LocalDB)\\v11.0;AttachDbFilename=|DataDirectory|\\TestDB.mdf;Integrated Security=True;Connect Timeout=30";
using (SqlConnection conn = new SqlConnection(conStr))
{
//with the call to strSQLSchema, we get the table involved in the query, to retrieve the fields and properties
SqlCommand cmd = new SqlCommand(strSQLSchema(strSql), conn);
SqlDataAdapter adapter = new SqlDataAdapter(cmd);
try
{
adapter.Fill(dt);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
this.dgvColumns.DataSource = dt;
}
private void btnPreview_Click(object sender, EventArgs e)
{
//We must pass the sql query to preview
string strSql = this.txtQuery.Text;
SQLQueryDataPreview qp = new SQLQueryDataPreview(strSql);
qp.Show();
}
private string strSQLSchema(string sqlQuery)
{
//we cut the "SELECT " start
sqlQuery = sqlQuery.ToUpper();
sqlQuery = sqlQuery.Substring(7);
//we take all the fields until the FROM
int myIndex = sqlQuery.IndexOf("FROM");
sqlQuery = sqlQuery.Substring(0, myIndex);
sqlQuery = sqlQuery.Trim();
sqlQuery = sqlQuery.Replace(" ", string.Empty);
sqlQuery = sqlQuery.Replace("\r\n", string.Empty);
//Here we add all fields to a list... so far, "*" is not allowed, and all fields should be written [Table].[Name]
string[] myFields = sqlQuery.Split(new char[] {' ', ','});
List <string> myTables = new List<string>();
//We will use this WHERE to find the fields in the SCHEMA. This WHERE first sentence helps to construct a valid where
//and avoid problems with the 'OR' clause in each loop.
string myWhere = "TABLE_NAME + '.' + COLUMN_NAME = ''";
for (int i = 0; i < myFields.Count(); i++)
{
//here we take the table prefix and add it to an array
int tableIndex = myFields[i].IndexOf(".");
if (tableIndex != -1)
{
myTables.Add(myFields[i].Substring(0, tableIndex));
myWhere += "OR (TABLE_NAME + '.' + COLUMN_NAME = '" + myFields[i] + "')";
}
}
//this is a List where we keep the tables derivated from names. We just copy the list generated before with a DISTINCT to eliminate duplicates.
myTables = myTables.Distinct().ToList();
string schema = "SELECT Table_Name, Column_Name, Data_Type FROM INFORMATION_SCHEMA.COLUMNS WHERE " + myWhere;
return schema;
}
}

How to pass a C# variable with apostrophe through MySql

I'm having a problem inputting variables into my database. I've seen other posts on how to pass a variable through by just escaping it, but those solutions do not apply because I am getting my variable's through an API. I'm cycling though data with a foreach loop by the way.
level = "" + x.Account_Level + "";
name = "" + x.name + "";
command.CommandText = "INSERT INTO `data` (`level`, `name`) VALUES(" + level + ", " + name + ")";
command.ExecuteNonQuery();
Sometimes, a variable will come back with an apostrophe and will screw up the code. Is it possible to insert a slash before every apostrophe or is there a way like in PHP to just push the whole variable through with single quotes? Thanks!
Edit:
Would this work? I think I need to add the i to change the name of the parameter each loop, due to it claiming the parameter as already declared.
using (var web = new WebClient())
{
web.Encoding = System.Text.Encoding.UTF8;
var jsonString = responseFromServer;
var jss = new JavaScriptSerializer();
var MatchesList = jss.Deserialize<List<Matches>>(jsonString);
string connectString = "Server=myServer;Database=myDB;Uid=myUser;Pwd=myPass;";
MySqlConnection connect = new MySqlConnection(connectString);
MySqlCommand command = connect.CreateCommand();
int i = 1;
connect.Open();
foreach (Matches x in MatchesList)
{
command.CommandText = "INSERT INTO `data` (`level`, `name`) VALUES(?level" + i + ", ?name" + i + ")";
command.Parameters.AddWithValue("level" + i, x.Account_Level);
command.Parameters.AddWithValue("mode" + i, x.name);
command.ExecuteNonQuery();
i++;
}
connect.Close();
}
The quick and dirty fix is to use something like:
level = level.Replace("'","whatever");
but there are still problems with that. It won't catch other bad characters and it probably won't even work for edge cases on the apostrophe.
The best solution is to not construct queries that way. Instead, learn how to use parameterised queries so that SQL injection attacks are impossible, and the parameters work no matter what you put in them (within reason, of course).
For example (off the top of my head so may need some debugging):
MySqlCommand cmd = new MySqlCommand(
"insert into data (level, name) values (?lvl, ?nm)", con);
cmd.Parameters.Add(new MySqlParameter("lvl", level));
cmd.Parameters.Add(new MySqlParameter("nm", name));
cmd.ExecuteNonQuery();

Unknown Error : insufficient parameters supplied to the command

in C# project , I have made a datagridview in my form that has some columns.column[0]& column[1] names are fix (day and date) and the other column names are variable and will change by user.these columns have time period thatsis shown with starting and finishing time.
such as from 6 am to 14 pm is shown as 6_14 as columns name.we have a listbox that has variable number of items(counter "i").
///sqlite doesn't accept columns name that start and finish with Numbers.I added word "f" to start and end of each
///column name
string data_str = "";
string data_str2="";
for (int i = 0; i < listBox1.Items.Count;i++ )
{
string temp = "f"+ listBox1.Items[i].ToString()+"f";
data_str = data_str + temp +",";
string temp2 = "#"+listBox1.Items[i].ToString()+",";
data_str2=data_str2+temp2;
}
data_str=data_str.TrimEnd(',');
data_str2=data_str2.TrimEnd(',');
in first step,I made two columns "day" & "date" in data table in my database and imported my data to it successfully.(It works)
string Q_insert = "insert into " + table_name + " (day,date) values (#day,#date)";
SQLiteConnection connect = new SQLiteConnection(connection_string);
SQLiteCommand insert_cmd = new SQLiteCommand(Q_insert, connect);
foreach (DataGridViewRow row in shift_datagrid.Rows)
{
insert_cmd.Parameters.AddWithValue("#day", row.Cells[0].Value.ToString().Trim());
insert_cmd.Parameters.AddWithValue("#date", row.Cells[1].Value.ToString().Trim());
connect.Open();
insert_cmd.ExecuteNonQuery();
connect.Close();
}
in second step,I need to import user data from datagridview to data table but the error takes place.(it doesn't work)
int col_cnt = listBox1.Items.Count;
Q_insert = "insert into " + table_name + " (" + data_str + ") values (" + data_str2 + ")";
connect = new SQLiteConnection(connection_string);
insert_cmd = new SQLiteCommand(Q_insert, connect);
foreach (DataGridViewRow row in shift_datagrid.Rows)
{
string temp1 = "";
for (int i = 0; i < col_cnt; i++)
{
temp1 = "\"#" + listBox1.Items[i].ToString() +"\"";
insert_cmd.Parameters.AddWithValue(temp1, row.Cells[i + 2].Value.ToString().Trim());
}
connect.Open();
insert_cmd.ExecuteNonQuery();
connect.Close();
}
unfortunately, this error occurs:
unknown Error : Insufficient parameters supplied to the command
I googled this error and checked solution ways for same problems but they were not useful for my problem and they couldn't help me anyway.
this is the example of output command strings that insert to data to database (two steps):
1. Insert into [table_name] (day,date) values (#day,#date) -------------->(it works)
2. Insert into [table_name] (f6_14f,f14_22f,f22_6f) values (#6_14,#14_22,#22_6) ------->(it doesn't work)
please help me
thanks
The following may be causing the error:
temp1 = "\"#" + listBox1.Items[i].ToString() +"\"";
insert_cmd.Parameters.AddWithValue(temp1, row.Cells[i + 2].Value.ToString().Trim());
Syntax requires that you don't construct the # as part of the variable value.# is not data. Use it as part of the variable name as you did before like this:
insert_cmd.Parameters.AddWithValue("#Col1",listBox1.Items[i+2].Value.ToString().Trim());
Where #Col1 is a column name of your table.
I don't think you can build the parameter name in a for loop, if so, you have to list the insert statements with each column name parameter prefixed with # as in the above example/code.

How to solve the maximum lenght error( it is too long ) in sql query c#

I have a method which includes sql statement . it is
public Boolean addRSS(string RSS_title, string Description, DateTime datetime, string RSS_Link, string user_name, float rate)
{
// Console.WriteLine(MyString.Remove(5, 10));
// string a = date.ToString().Replace('.', '-');
Boolean res = false;
string sql = "INSERT INTO My_RSS ( RSS_Title,RSS_Description,RSS_Date,RSS_Link,RSS_Rate,UserName) values('"
+
RSS_title + "','" +
"FFFFFFFFFFFFFFFFFFFFFFFFFAAASDASDASDASD" +
"', SYSUTCDATETIME(),'" +
RSS_Link + "'," +
rate + ",'"+
user_name +
"')";
try
{
// hasan = hasan.Insert(c, hasan);
SqlCommand cmd = new SqlCommand(sql, Connect());
cmd.ExecuteNonQuery();
res = true;
}
catch (Exception)
{
res = false;
}
return res;
}
It gives the error when I try to enter this input http://rss.feedsportal.com/c/32727/f/510887/s/1da50441/l/0Lekonomi0Bmilliyet0N0Btr0Cenflasyon0Eyuzde0E50Ee0Einene0Ekadar0Esikacak0E0Cekonomi0Cekonomidetay0C210B0A30B20A120C15181930Cdefault0Bhtm/story01.htm to "link column" and
it gives error which is
Incorrect syntax near 'e'.
The identifier that starts with 'Lekonomi0Bmilliyet0N0Btr0Cenflasyon0Eyuzde0E50Ee0Einene0Ekadar0Esikacak0E0Cekonomi0Cekonomidetay0C210B0A30B20A120C15181930Cdefau' is too long. Maximum length is 128.
Unclosed quotation mark after the character string ')'.
Also,In the sql side this colum is varchar(455)
The error is saying that the identifier name is too long; this combined with the unclosed quotation mark error means you probably missed an opening quote. That is, you have this:
INSERT INTO Foo ( A ) VALUES ( AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA')
instead of
INSERT INTO Foo ( A ) VALUES ( 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA')
You shouldn't be building your queries via string concatentation; this is one of the reasons. Parameterized queries will get the quoting right for you. (Note: you don't need to be using stored procs to use parameterized queries.)
var sql = "INSERT INTO My_RSS ( Title, Description, Date, Link, Rate, Name )
VALUES ( #Title, #Desc, #PostDate, #Link, #Rate, #Name )";
SqlCommand cmd = new SqlCommand(sql, Connect());
cmd.Parameters.Add("#Title", SqlDbType.VarChar, 100).Value = RSS_title;
cmd.Parameters.Add("#Desc", SqlDbType.VarChar, 8192).Value = RSS_description;
cmd.Parameters.Add("#PostDate", SqlDbType.SmallDateTime).Value = DateTime.Now;
cmd.Parameters.Add("#Rate", SqlDbType.Int).Value = rate;
etc.
You Can also add SET QUOTED_IDENTIFIER OFF before 'sql' string and SET QUOTED_IDENTIFIER On after 'sql'
QUOTED IDENTIFIER ON/OFF:
This specifies the setting for usage of double quotation. IF this is on, double quotation mark is used as part of the SQL Server identifier (object name). This can be useful in situations in which identifiers are also SQL Server reserved words.
sql = "SET QUOTED_IDENTIFIER OFF " + sql + " SET QUOTED_IDENTIFIER OFF ";
SqlCommand cmd = new SqlCommand(sql, Connect());
cmd.ExecuteNonQuery();
res = true;
You should use this in this case.

Categories

Resources