As some of you may of seen from my previous post I'm new to using C# to create websites (Although I have a fair bit of experience using it for Windows Forms apps). The powers that be are tempting me away from PHP but I keep failing at what I consider the basics.
Anyway, this is my issue. I am trying to create a simple entry into a SQL database. I know my connection to the DB is fine as I can reel off SELECT queries all day long but I'm having trouble with using Insert.
Heres my code:
string filename = "abc123.jpg";
SqlConnection link = new SqlConnection(//you dont need to see my data here ;));
string sqlcode = "INSERT INTO file_uploads (upload_filename VALUES ("+filename+")";
SqlCommand sql = new SqlCommand(sqlcode,link);
link.open();
sql.ExecuteNonQuery();
This results in "Invalid column name abc123.jpg" returned from the try/catch.
Any help would be appreciated. (I wish they would let me do this in PHP lol!)
Thanks,
Tripbrock
You are missing a parenthesis after the column name and the value represents a string and as such must be enclosed in quotes:
string sqlcode = "INSERT INTO file_uploads (upload_filename) " +
"VALUES ('"+filename+"')";
However, the correct way would be to use a parameterized query:
string filename = "abc123.jpg";
SqlConnection link = new SqlConnection(/*you dont need to see my data here ;)*/);
string sqlcode = "INSERT INTO file_uploads (upload_filename) VALUES (#filename)";
SqlCommand sql = new SqlCommand(sqlcode,link);
sql.Parameters.AddWithValue("#filename", filename);
link.open();
sql.ExecuteNonQuery();
your SQL is bad formatted. Try this :
string sqlcode = "INSERT INTO file_uploads (upload_filename) VALUES ('"+filename+"')";
Where upload_filename is a name of the column
Really you should be parameterising your queries - this reduces the risk of injection attacks:
string filename = "abc123.jpg";
using( SqlConnection link = new SqlConnection(/*...*/;)) )
{
// sql statement with parameter
string sqlcode = "INSERT INTO file_uploads (upload_filename) VALUES (#filename)";
using( SqlCommand sql = new SqlCommand(sqlcode,link) )
{
// add filename parameter
sql.Parameters.AddWithValue("filename", filename);
link.open();
sql.ExecuteNonQuery();
}
}
Also note the using statements - these make sure that the connection and command objects are disposed of.
Try
string sqlcode = "INSERT INTO file_uploads (upload_filename) VALUES ('"+filename+"')";
You were missing a closing parentheses.
Don't know if it is a typo but the line should be:
string sqlcode = "INSERT INTO file_uploads (upload_filename) VALUES ('"+filename+"')";
Notice the ) after upload_filename.
Also also added the single quotes around the filename.
But you probably want to use a parameterized query:
string sqlcode = "INSERT INTO file_uploads (upload_filename) VALUES (#filename)";
Then use command.Parameters to add the actual value.
looks like you are missing a bracket:
string sqlcode = "INSERT INTO file_uploads (upload_filename VALUES ("+filename+")";
Should be
string sqlcode = "INSERT INTO file_uploads (upload_filename) VALUES ('"+filename+"')";
Also, to avoid SQL injection attacks you can use the SQLCommand objects like so.
using (SQLCommand oSQLCommand = new SQLCommand("INSERT INTO file_uploads (upload_filename) VALUES ( #FileName )")
{
oSQLCommand.Parameters.AddWithValue("#FileName", filename);
oSQLCommand.ExecuteNonQuery();
}
Related
I have a problem with executing a sql command to the DB. The command should add a new user to the 'users' table.
But when I run the code, I get this Exception on:
command.ExecuteNonQuery();
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.Data.OleDb.OleDbException: Syntax error in INSERT INTO statement.
this is the code of the page - GetSignIn.cshtml :
#{
string Uname = Request["name"];
string userName = Request["userName"];
string pass = Request["passWord"];
string pic = Request["pic"];
string privacy = Request["privacy"];
if(pic == null)
{
pic = "Shared/defaultPic.jpg";
}
System.Data.OleDb.OleDbConnection connection = new System.Data.OleDb.OleDbConnection();
connection.ConnectionString = #"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\Users\Etay\Documents\Visual Studio 2012\WebSites\Josef\Shared\users.mdb";
try
{
System.Data.OleDb.OleDbCommand command = new System.Data.OleDb.OleDbCommand();
command.Connection = connection;
connection.Open();
command.CommandText = "INSERT INTO users (userName,passWord,Uname,pic) VALUES ('" + userName + "', '" + pass + "', '" + Uname + "', '" + pass + "', " + pic + ")";
command.ExecuteNonQuery();
Response.Redirect("../HtmlPage.html");
}
finally
{
connection.Close();
}
}
What should I change in my code? Why is it happening? Where is the syntax error in the INSERT INTO?
Use parameterized queries. Here is your statement rewritten to make use of them.
I replaced your try/finally with a using block although your try/finally was acceptable.
Parameterized queries prevent errors and Sql Injection Attacks. An error could occur in your existing code if I were to submit a tick as a part of my user name or password. In the current form this would result in an exception. This is because the tick character is used to quote strings in sql syntax.
using (System.Data.OleDb.OleDbConnection connection = new System.Data.OleDb.OleDbConnection())
{
connection.ConnectionString = #"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\Users\Etay\Documents\Visual Studio 2012\WebSites\Josef\Shared\users.mdb";
using (System.Data.OleDb.OleDbCommand command = new System.Data.OleDb.OleDbCommand())
{
command.Connection = connection;
command.CommandText = "INSERT INTO users (userName,passWord,Uname,pic) VALUES (?,?,?,?)";
command.Parameters.Add(userName);
command.Parameters.Add(pass);
command.Parameters.Add(Uname);
command.Parameters.Add(pic);
connection.Open();
command.ExecuteNonQuery();
}
}
About parameters for an OleDb connection from OleDbCommand.Parameters
Remarks
The OLE DB .NET Provider does not support named parameters for passing parameters to an SQL statement or a stored procedure called by an OleDbCommand when CommandType is set to Text. In this case, the question mark (?) placeholder must be used. For example:
SELECT * FROM Customers WHERE CustomerID = ?
Therefore, the order in which OleDbParameter objects are added to the OleDbParameterCollection must directly correspond to the position of the question mark placeholder for the parameter in the command text.
What should I change in my code?
Change to parameters (that also fixes the problem that you don;t have quotes around the pic value)
Remove the second instance of pass in your values
command.CommandText = "INSERT INTO users (userName,passWord,Uname,pic) VALUES (#userName, #pass, #Uname, #pic)";
command.Parameters.Add("#userName").Value = userName;
.. etc.
It's unclear what the type if pic is - you are passing a string but I can;t tell of the column stores a file path or if you are indending to serialize the file and store it in a pinary field.
You set 4 fields after the "INTO" clause, however you're passing 5 parameters:
"INSERT INTO users (userName,passWord,Uname,pic) VALUES ('" + userName + "', '" + pass + "', '" + Uname + "', '" + pass + "', " + pic + ")";
Just add the fifth field, or remove one parameter from the VALUES part
Please check take a look at your Insert statement, it looks like that you provided password value twice.
The number of query values and the destination fields should be same in an INSERT statement.
You have the wrong number parameters in your insert statement. For clarity, why not use string.Format to keep everything uniform? (Assuming these are all string types)
var rawSql = #"Insert INTO Users (userName,passWord,Uname,pic) VALUES ('{0}','{1}','{2}','{3}')";
command.CommandText = string.Format(rawSql, userName, pass, Uname, pic);
command.ExecuteNonQuery();
However, it also looks like you probably want to include that 5th parameter as well - just extend the format :
var rawSql = #"Insert INTO Users (userName,passWord,Uname,pic, privacy) VALUES ('{0}','{1}','{2}','{3}','{4}')";
command.CommandText = string.Format(rawSql, userName, pass, Uname, pic, privacy);
command.ExecuteNonQuery();
Since most of the answers failed to address the SQL Injection vulnerability, here's an example with parameterized queries. In addition to preventing SQL Injection attacks, it also makes it easier to troubleshoot these types of issues, and you don't need to worry about quoting or not quoting parameters.
System.Data.OleDb.OleDbConnection connection = new System.Data.OleDb.OleDbConnection();
connection.ConnectionString = #"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\Users\Etay\Documents\Visual Studio 2012\WebSites\Josef\Shared\users.mdb";
try
{
System.Data.OleDb.OleDbCommand command = new System.Data.OleDb.OleDbCommand();
command.Connection = connection;
connection.Open();
command.CommandText = "INSERT INTO users (userName, passWord, Uname, pic, privacy) VALUES (?, ?, ?, ?, ?)";
command.Parameters.Add(userName);
command.Parameters.Add(pass);
command.Parameters.Add(name);
command.Parameters.Add(pic);
command.Parameters.Add(privacy);
command.ExecuteNonQuery();
Response.Redirect("../HtmlPage.html");
}
finally
{
connection.Close();
}
Tnx 4 the help
It happend to be a problem with the database - you can not apply a INSERT INTO statement where the column name is "password". "password" is a Reserved word
in SQL.
Tnx again,
Etay
this works:
string sqlStr = string.Format("INSERT INTO tblFiles (filename,downloadname,description,category,length,parts,checksum,isEncrypted,uploaderIp) VALUES ('{0}','{1}','{2}','{3}',{4},{5},'{6}',{7},'{8}');",
newFile.Name.Replace("'", "''"), newFile.DownloadName.Replace("'", "''"), newFile.Description, newFile.Category, newFile.Length, newFile.Parts, newFile.Checksum, newFile.IsEncrypted, GetPeerIp());
this doesn't:
string sqlStr = string.Format("INSERT INTO tblFiles (filename,downloadname,description,category,length,parts,checksum,isEncrypted,password,uploaderIp) VALUES ('{0}','{1}','{2}','{3}',{4},{5},'{6}',{7},'{8}','{9}');",
newFile.Name.Replace("'", "''"), newFile.DownloadName.Replace("'", "''"), newFile.Description, newFile.Category, newFile.Length, newFile.Parts, newFile.Checksum, newFile.IsEncrypted, password, GetPeerIp());
Exception I get:
$exception {"Syntax error in INSERT INTO statement."} System.Exception {System.Data.OleDb.OleDbException}
my database looks like this.
I couldn't find any problem with it. Any ideas?
Thanks
Password is a reserved keyword in MS-Access sql. If you have a field with that name you need to encapsulate that name between square brackets (better change it now)
string sqlStr = #"INSERT INTO tblFiles
(filename,downloadname,description,category,length,parts,
checksum,isEncrypted,[password],uploaderIp) VALUES (.....)";
Said that, please, remove all that string concatenations and use a parameterized query. Not only this is more safe (prevents Sql Injections) but also removes all the problems with quoting and correct parsing of dates and decimal numbers
string sqlStr = #"INSERT INTO tblFiles
(filename,downloadname,description,category,length,parts,
checksum,isEncrypted,[password],uploaderIp) VALUES
(#file, #down, #desc, #cat, #len, #parts, #check, #enc, #pass, #up)";
OleDbCommand cmd = new OleDbCommand(sqlStr, connection);
cmd.Parameters.Add("#file", OleDbType.VarWChar).Value = newFile.Name;
cmd.Parameters.Add("#down", OleDbType.VarWChar).Value = newFile.DownloadName;
... and so on for all other parameters respecting the OleDbType of the column....
cmd.ExecuteNonQuery();
Notice how your query is more clear and understandable and how you don't need to call a lot of Replace just to get rid of possible embedded single quotes.
I'm trying to insert this byte array into a SQL Server database, the column data type is varbinary and this is my code in C#
SqlParameter param = new SqlParameter("#buffer", SqlDbType.VarBinary, 8000);
param.Value = buffer;
string _query = "INSERT INTO [dbo].[Files] (FileID, Data, Length) VALUES ('" + uID + "','" + buffer + "','" + buffer.Length + "')";
using (SqlCommand comm = new SqlCommand(_query, conn))
{
comm.Parameters.Add(param);
try
{
conn.Open();
comm.ExecuteNonQuery();
}
catch (SqlException ex)
{
return Request.CreateResponse(HttpStatusCode.OK, "Something went wrong : " + ex.Message);
}
finally
{
conn.Close();
}
}
I also tried it with #buffer inside the _query string instead of buffer but I keep getting the error :
Converting from varchar to varbinary is not allowed use the CONVERT command to execute this query
and I used Convert and it is saved successfully, but when I retrieve it, it retrieves the first 14 bytes only,
byte[] bytearr = (byte[])row["Data"];
I've been looking and found nothing. Can you please help me in storing the bytes and retrieving it?
You send your values as literals in your SQL query. This is a bad idea, but first the problem with your query:
A varbinary literal in SQL Server is not a string (enclosed in quotes), but a very big hex number, looking something like this example: SET #binary = 0x1145A5B9C98.
By the way, I find it strange that you enclose your ID and your Length in quotes as well. I assume they are integers, so they should be specified without quotes: SET #i = 2. It may still work in your case, because the string is going to be converted to integer by SQL Server on the fly. It's just confusing and less efficient.
Now, please never do SQL requests by concatenating literals like that. Use SQL parameters instead. Something like that:
cmd.CommandText = "INSERT INTO Files (FileId, Data, Length) VALUES (#id, #data, #length)";
cmd.Parameters.AddWithValue("id", 3);
cmd.Parameters.AddWithValue("data", someByteArray);
cmd.Parameters.AddWithValue("length", someByteArray.Length);
If you want to make even simpler, look into some helper. I recommend Dapper.
Lastly, I note that you are storing both a varbinary and its length. That's not required, you can always get the length of a varbinary stored in SQL Server like this: SELECT LEN(Data) FROM Files
This is how I am doing it from one of my projects. Also to add to one of the comments someone made about sql injection attacks, it is good practice to not concat strings together to make up a sql string. Instead use command parameters like I am doing below with the name param. This prevents most kinds of sql injection attacks.
Loading:
const string sql = "select data from files where name = #name";
using (var cn = _db.CreateConnection())
using (var cm = cn.CreateTextCommand(sql))
{
cm.AddInParam("name", DbType.String, name);
cn.Open();
return cm.ExecuteScalar() as byte[];
}
Saving:
const string sql = "insert into files set data = #data where Name = #name";
using (var cn = _db.CreateConnection())
using (var cm = cn.CreateTextCommand(sql))
{
cm.AddInParam("name", DbType.String, name);
cm.AddInParam("data", DbType.Binary, data);
cm.ExecuteNonQuery();
}
I iterate over an external source and get a list of strings. I then insert them into the DB using:
SqlCommand command = new SqlCommand(commandString, connection);
command.ExecuteNonQuery();
Where commandString is an insert into command. i.e.
insert into MyTable values (1, "Frog")
Sometimes the string contains ' or " or \ and the insert fails.
Is there an elegant way to solve this (i.e. #"" or similar)?
Parameters.
insert into MyTable values (#id, #name)
And
int id = 1;
string name = "Fred";
SqlCommand command = new SqlCommand(commandString, connection);
command.Parameters.AddWithValue("id", id);
command.Parameters.AddWithValue("name", name);
command.ExecuteNonQuery();
Now name can have any number of quotes and it'll work fine. More importantly it is now safe from sql injection.
Tools like "dapper" (freely available on NuGet) make this easier:
int id = 1;
string name = "Fred";
connection.Execute("insert into MyTable values (#id, #name)",
new { id, name });
You should look into using parameterized queries. This will allow you insert the data no matter the content and also help you avoid possible future SQL injection.
http://csharp-station.com/Tutorial/AdoDotNet/Lesson06
http://www.c-sharpcorner.com/uploadfile/puranindia/parameterized-query-and-sql-injection-attacks/
string connectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\\Samples\\login.mdb";
string uname, pass;
uname = textBox1.Text;
pass = textBox2.Text;
OleDbConnection myConnection = new OleDbConnection(connectionString);
myConnection.Open();
string query = "insert into LOGIN_TABLE (UserName, Password) VALUES ('" + textBox1.Text.ToString() + "','" + textBox2.Text.ToString() + "') ";
OleDbCommand myCommand = new OleDbCommand(query, myConnection);
//myCommand.CommandText = query;
OleDbParameter myParm = myCommand.Parameters.Add("#uname", OleDbType.VarChar, 50);
myParm.Value = textBox1.Text;
myParm = myCommand.Parameters.Add("#pass", OleDbType.VarChar, 50);
myParm.Value = textBox2.Text;
myCommand.ExecuteNonQuery();
myConnection.Close();
From the docs for OleDbCommand.Parameters:
The OLE DB .NET Provider does not
support named parameters for passing
parameters to an SQL statement or a
stored procedure called by an
OleDbCommand when CommandType is set
to Text. In this case, the question
mark (?) placeholder must be used.
There's an example on the same page.
However, you're not even using parameters in your SQL query. You're inviting a SQL injection attack by embedding the user input directly into the SQL and then also adding parameters.
Your query should just be:
String query = "insert into LOGIN_TABLE (UserName, Password) VALUES (?, ?)";
It looks like you can still give parameters names, even if they're not used - so just the change above may be enough.
EDIT: Is it possible that UserName or Password are reserved names? Try escaping them - I know in SQL Server it would be [UserName], [Password] but I don't know if that's true in Access. What happens if you try to execute the same SQL in Access, by the way?
The data you are passing as parameters might have single-quotes, ', in it.
Try this textBox2.Text.Replace("'","''") when assigning values to the parameters.
One more thing, it is not necessary to use parameters when handling simple texts and numbers in simple queries.
Your query should be like this.
string query = "insert into LOGIN_TABLE (UserName, Password) VALUES ( #uname, #pass )";
Now after that write your code, and everything will be work for you.
Whenever you are reading value from textbox, use Trim() as textBox.Text.Trim().
Sorry it will be working for SqlConnection.
Thanks