How does sanitize the sql parameter - c#

I write these code all are working fine but there is a warning coming that sanitize the sql parameter.
private DataSet ExcelToDataSet(string fileData)
{
DataSet ds = new DataSet();
string connectionString = GetConnectionString(fileData);
using (OleDbConnection conn = new OleDbConnection(connectionString))
{
conn.Open();
OleDbCommand cmd = new OleDbCommand();
cmd.Connection = conn;
// Get all Sheets in Excel File
DataTable dtSheet = conn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null);
// Loop through all Sheets to get data
foreach (DataRow dr in dtSheet.Rows)
{
string sheetName = dr["TABLE_NAME"].ToString();
if (!sheetName.EndsWith("$"))
continue;
// Get all rows from the Sheet
cmd.CommandText = "SELECT * FROM [" + sheetName + "]";
DataTable dt = new DataTable();
dt.TableName = sheetName;
OleDbDataAdapter da = new OleDbDataAdapter(cmd);
da.Fill(dt);
ds.Tables.Add(dt);
}
cmd = null;
conn.Close();
}
return (ds);
}
I have to sanitize the following line
cmd.CommandText = "SELECT * FROM [" + sheetName + "]";

Usually, when writing SQL Statements, you need to use parameters to pass the data from user input into the sql statement, to prevent SQL Injection attacks. That's why you get this warning. However, there is nothing you can do about it since it's impossible to parameterize identifiers in SQL, and you don't need to do it because you are not concatenating user input, and you are not running this query on a database, so even if you could use SQL injection, the worst you can do is corrupt a single file

UPDATE: I did not notice this was a OleDbConnection, the database you are connecting to may not have the same functionality to quote an identifier. I am leaving this answer here in case someone comes across this question and needs the same thing but for a SQL connection.
As the others have said, there is no need to worry about the warning in this case as the data is not coming from user data.
However everyone is wrong about the fact you cannot parameterize an identifier. You need to build the query dynamically server side and use the QUOTENAME function but it is possible.
foreach (DataRow dr in dtSheet.Rows)
{
string sheetName = dr["TABLE_NAME"].ToString();
if (!sheetName.EndsWith("$"))
continue;
// Get all rows from the Sheet
cmd.CommandText = #"
declare #sql nvarchar(114);
set #sql = N'select * from ' + quotename(#sheetname)
exec sp_executesql #sql
";
cmd.Parameters.Clear();
cmd.Parameters.Add("#sheetname", SqlDbType.NVarChar, 100).Value = sheetName;
DataTable dt = new DataTable();
dt.TableName = sheetName;
OleDbDataAdapter da = new OleDbDataAdapter(cmd);
da.Fill(dt);
ds.Tables.Add(dt);
}
This will generate a dynamic query that will safely escape the name of the table.

Related

How to insert a datatable to an access database in C#

I have 2 table in an access database
now I want to select from one table and insert them into another one.
this is my code but it shows an exception in line Cmd.ExecuteNonQuery();
{"Syntax error (missing operator) in query expression 'System.Object[]'."}
the code is :
public static void SetSelectedFeedIntoDB(Form2 frm2)
{
string StrCon = System.Configuration.ConfigurationManager.ConnectionStrings["FeedLibraryConnectionString"].ConnectionString;
OleDbConnection Connection = new OleDbConnection(StrCon);
OleDbDataAdapter DataA = new OleDbDataAdapter("Select * from FeedLibrary where ID=" + frm2.FeedSelectListBox.SelectedValue, Connection);
DataTable DTable = new DataTable();
DataA.Fill(DTable);
OleDbCommand Cmd = new OleDbCommand();
Cmd.Connection = Connection;
Connection.Open();
foreach (DataRow DR in DTable.Rows)
{
Cmd.CommandText = "insert into SelectedFeeds Values(" + DR.ItemArray + ")";
Cmd.ExecuteNonQuery();
}
Connection.Close();
}
what should I do to fix this?
Your error is caused by the fact that you are concatenating the ItemArray property of a DataRow to a string. In this case the ItemArray (that is an instance of an object[]) has no method that automatically produces a string from its values and thus returns the class name as a string "object[]" but of course this produces the meaningless sql string
"insert into SelectedFeeds Values(object[])";
But you could simply build a SELECT .... INTO statement that will do everything for you without using DataTables and Adapters
string cmdText = #"SELECT FeedLibrary.* INTO [SelectedFeeds]
FROM FeedLibrary
where ID=#id";
using(OleDbConnection Connection = new OleDbConnection(StrCon))
using(OleDbCommand cmd = new OleDbCommand(cmdText, Connection))
{
Connection.Open();
cmd.Parameters.Add("#id", OleDbType.Integer).Value = Convert.ToInt32( frm2.FeedSelectListBox.SelectedValue);
cmd.ExecuteNonQuery();
}
However, the SELECT ... INTO statement creates the target table but gives error if the target table already exists. To solve this problem we need to discover if the target exists. If it doesn't exist we use the first SELECT ... INTO query, otherwise we use a INSERT INTO ..... SELECT
// First query, this creates the target SelectedFeeds but fail if it exists
string createText = #"SELECT FeedLibrary.* INTO [SelectedFeeds]
FROM FeedLibrary
where ID=#id";
// Second query, it appends to SelectedFeeds but it should exists
string appendText = #"INSERT INTO SelectedFeeds
SELECT * FROM FeedLibrary
WHERE FeedLibrary.ID=#id";
using(OleDbConnection Connection = new OleDbConnection(StrCon))
using(OleDbCommand cmd = new OleDbCommand("", Connection))
{
Connection.Open();
// Get info about the SelectedFeeds table....
var schema = Connection.GetSchema("Tables",
new string[] { null, null, "SelectedFeeds", null});
// Choose which command to execute....
cmd.CommandText = schema.Rows.Count > 0 ? appendText : createText;
// Parameter #id is the same for both queries
cmd.Parameters.Add("#id", OleDbType.Integer).Value = Convert.ToInt32( frm2.FeedSelectListBox.SelectedValue);
cmd.ExecuteNonQuery();
}
Here we have two different queries, the first one create the SelectedFeeds table as before, the second one appends into that table.
To discover if the target table has already been created I call Connection.GetSchema to retrieve a datatable (schema) where there is a row if the table SelectedFeeds exists or no row if there is no such table.
At this point I set the OleDbCommand with the correct statement to execute.

Displaying rows from table into datagridview with matched column value

I have a list of string which contain names and a database table what i want to do is to display the rows from the table in datagridview. All rows which contain the name column value same as any of the list item will be displayed into datagrid view.I wrote the code for this using for loop but it is showing only last matched row in datagridview.
DBConnection.ConnectionString = #"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=FacesDatabase.mdb";
DBConnection.Open();
OleDbCommand command = new OleDbCommand();
command.Connection = DBConnection;
for(i=0;i<MatchName.ToArray().Length;i++)
{
string query = "Select FaceID,FaceName,RollNo,FaceImage from " + tableName + " where FaceName='" + MatchName[i].ToString() + "'";
command.CommandText = query;
OleDbDataAdapter da=new OleDbDataAdapter(command);
DataTable dt=new DataTable();
da.Fill(dt);
dataGridView1.DataSource=dt;
}
DBConnection.Close();
You can use the IN SQL key word:
DBConnection.ConnectionString = #"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=FacesDatabase.mdb";
DBConnection.Open();
OleDbCommand command = new OleDbCommand();
command.Connection = DBConnection;
string query = "Select FaceID,FaceName,RollNo,FaceImage from " + tableName + " where FaceName IN ('"+ string.Join("','",MatchName.ToArray())+ "')";
command.CommandText = query;
OleDbDataAdapter da=new OleDbDataAdapter(command);
DataTable dt=new DataTable();
da.Fill(dt);
dataGridView1.DataSource=dt;
DBConnection.Close();
In your example what you're doing is querying the db for each "MatchName" (whatever that is) and for every resultset you're getting back you're assigning it as the datagrid's datasource. Therefore you're only seeing the last resultset since you're overwriting previous results.
Using the IN key word you're only hitting the db once and binding the grid to the data source once.
I also recommend using command parameters instead of building your query they way you are using string concatenation.
You are overwriting your gridview datasource. You can also do something like,
dataGridView1.DataSource = null;
for (i = 0; i < MatchName.ToArray().Length; i++)
{
string query = "Select FaceID,FaceName,RollNo,FaceImage from " + tableName + " where FaceName='" + MatchName[i].ToString() + "'";
command.CommandText = query;
OleDbDataAdapter da = new OleDbDataAdapter(command);
DataTable dt = new DataTable();
da.Fill(dt);
if (dataGridView1.DataSource != null)
{
DataTable dt2 = (DataTable)dataGridView1.DataSource;
dt.Rows.Cast<DataRow>().ToList().ForEach(x => dt2.ImportRow(x));
dt = dt2;
}
dataGridView1.DataSource = dt;
}

ms access database connection in a datagridview

What is the error of this code
connect = new OleDbConnection(coo);
connect.Open();
command.Connection = connect;
DataTable dt = new DataTable();
OleDbDataAdapter ODA = new OleDbDataAdapter("SELECT * FROM Items where itemno = '" + textBox1.Text + "'", connect);
ODA.Fill(dt);
dataGridView1.DataSource = dt;
after I run it, this is what happened
"Data type mismatch in criteria expression"
What should I do?
itemno is integer, that is why you are getting the error, remove the single quotes around the value. But, More importantly, Use Parameters with your query. You are prone to SQL Injection
using (var connect = new OleDbConnection(coo))
{
using (OleDbCommand command = new OleDbCommand("SELECT * FROM Items where itemno = ?", connect))
{
command.Parameters.Add(new OleDbParameter("#p1", OleDbType.Integer)
{
Value = textBox1.Text
});
DataTable dt = new DataTable();
OleDbDataAdapter ODA = new OleDbDataAdapter(command);
ODA.Fill(dt);
dataGridView1.DataSource = dt;
}
}
Couple of things to add:
Enclose your Command and Connection object in using statement.
You don't have to explicitly open a connection with DataAdapter. It will open the connection to the database.
OleDB uses positional parameter instead of named parameter

Oledb connection and query read only one column from excel spreadsheet [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How can i select specific columns from excel sheet in c#?
string strConn = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=|DataDirectory|2.xls;Extended Properties='Excel 8.0;HDR=no;'";
string query = "SELECT * FROM [Sheet1$]";
DataSet excelDataSet = new DataSet();
OleDbDataAdapter da = new OleDbDataAdapter(query, strConn);
da.Fill(excelDataSet);
GridView1.DataSource = excelDataSet;
GridView1.DataBind();
GridView1.HeaderRow.Cells[0].Text = "CheckNumber";
I have this code to read an Excel Spreadsheet being loaded from a website and being displayed in a gridview. I would like to simply just read column A on the spreadsheet. I think I should be able to change this string query = "SELECT * FROM [Sheet1$]"; but all my efforts have been futile. Can someone point me in the right direction, or is there a better way to do this.
it looks like the way to do this is simply
string sql = "SELECT F1, F2, F3, F4, F5 FROM [sheet1$];
Thanks for the comments everyone.
I believe your problem lies in the fact that a spreadsheet is not a database. A spreadsheet is under no obligation to be rectangular or have cells of the same type. So saying you want a column ASSUMES that that column exists for all rows and is of the same type. So before you issue SQL against it you need to convert to a vector of the same type.
Here is what I use to read an Excel Spreadsheet and return it as a DataTable and if you focus in on the following section where I am able to query all of the workbooks in the Spreadsheet by looping through the dtSchema DataTable object to find the names of the different worksheets:
public static DataTable GetExcelData(string connectionString)
{
string sql = string.Empty;
using (OleDbConnection cn = new OleDbConnection(connectionString))
{
using (OleDbDataAdapter adapter = new OleDbDataAdapter())
{
DataTable dt = new DataTable();
using (OleDbCommand command = cn.CreateCommand())
{
cn.Open();
DataTable dtSchema = cn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, new object[] { null, null, null, "TABLE" });
foreach (DataRow dr in dtSchema.Rows)
{
//Will Loop through the name of each Worksheet
Console.WriteLine(dr["Table_Name"]);
}
string firstSheetName = dtSchema.Rows[0].Field<string>("TABLE_NAME");
sql = "SELECT * FROM [" + firstSheetName + "]";
command.CommandText = sql;
adapter.SelectCommand = command;
adapter.Fill(dt);
if (dt.Rows.Count == 0)
{
OleDbDataReader reader = command.ExecuteReader();
dt.Load(reader);
}
cn.Close();
return dt;
}
}
}
}

OLEDB Parameterized Query

public void LoadDB()
{
string FileName = #"c:\asdf.accdb";
string query = "SELECT ID, Field1 FROM Table1 WHERE ID=? AND Field1=?";
string strConn = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + FileName;
OleDbConnection odc = new OleDbConnection(strConn);
dAdapter = new OleDbDataAdapter();
OleDbCommand cmd = new OleDbCommand(query,odc);
cmd.Parameters.Add("?", OleDbType.Integer, 5).Value = 1234;
cmd.Parameters.Add("?", OleDbType.BSTR, 5).Value ="asdf";
dAdapter.SelectCommand = cmd;
ds = new DataSet();
dAdapter.Fill(ds);
dataGridView1.DataSource = ds.Tables[0];
}
I'm trying to use parametrized query to bind the access file into the datagridview. It finds the column names fine, but the contents are empty.
How can I fix this issue?
Here is an example of how the parameterized queries work with CSharp, OleDB.
try
{
connw.Open();
OleDbCommand command;
command = new OleDbCommand(
"Update Deliveries " +
"SET Deliveries.EmployeeID = ?, Deliveries.FIN = ?, Deliveries.TodaysOrders = ? , connw);
command.Parameters.Add(new OleDbParameter("#EMPID", Convert.ToDecimal(empsplitIt[1])));
command.Parameters.Add(new OleDbParameter("#FIN", truckSplit[1].ToString()));
command.Parameters.Add(new OleDbParameter("#TodaysOrder", "R"));
catchReturnedRows = command.ExecuteNonQuery();//Commit
connw.Close();
}
catch (OleDbException exception)
{
MessageBox.Show(exception.Message, "OleDb Exception");
}
This will work with any sql statement, you must assign the question mark "?" to each parameter, and then below you must create the parameters and add them in the order of how you laid out the question marks to get the right data into the right field.
In my test program, the ds.Tables[0].Rows.Count datatable actually had 1 row returned (as there was one row in my test database that matched the query itself). If you put a break on this line you should be able to see whether or not data is getting into the datatable in the first place. Try this:
dataGridView1.DataSource = ds.Tables[0];
What does the front end binding of dataGridView1 look like? Running the query in Access could shed some light on the situation too.
Try without specifying column size in parameters:
cmd.Parameters.Add("?", OleDbType.Integer).Value = 1234;
cmd.Parameters.Add("?", OleDbType.BSTR).Value ="asdf";

Categories