What is wrong with this SQL query? - sql

I run this query
"insert into students (StudentName) values ('reza');insert into Records (RecordValue,StudentID)" +
" values (20,##IDENTITY)";
in C# and get following exception :
Characters found after end of SQL statement

I guess you want to retrieve the identity of the newly inserted student and then insert that into the "Records" table, right?
I would strongly suggest you use SCOPE_IDENTITY() instead of ##IDENTITY which has some problems if you have e.g. triggers on your table. Pinal Dave has a great blog post about those problems.
Also, if you call SQL Server from C#, I'd strongly recommend you use the native .NET SQL Provider (SqlConnection, SqlCommand, etc.) - not oledbcommand.
Try this
using (SqlConnection _con = new SqlConnection("server=(local);database=TEST;integrated security=SSPI;"))
{
string queryStmt = "INSERT INTO dbo.Students (StudentName) VALUES('reza'); " +
"INSERT INTO dbo.Records(RecordID, StudentID) VALUES (20, SCOPE_IDENTITY());";
using (SqlCommand _cmd = new SqlCommand(queryStmt, _con))
{
try
{
_con.Open();
_cmd.ExecuteNonQuery();
_con.Close();
}
catch (Exception exc)
{
string msg = exc.Message;
}
}
}
This certainly works, I just tested it successfully in my setting.

I just ran this code and it worked out:
SqlConnection cn = new SqlConnection("...");
SqlCommand cm = cn.CreateCommand();
cm.CommandText =
"INSERT INTO MyTable (FieldA) VALUES ('Sample'); " +
"INSERT INTO MyTable (FieldB) VALUES (##Identity); ";
cn.Open();
cm.ExecuteNonQuery();
Maybe you need to add a space after that first semicolon character.

You can do this command much as shown - you do not need to have a temporary variable nor do you need a "GO" or a space after the semicolon. I do agree with Marc_s that you should use SCOPE_IDENTITY() to avoid problems with other transactions sneaking a value in.
The question is: why do you have quotes around your statement and a semicolon at the end? Clearly you are pulling this from code and that is where I'd look. So...first, run this command in SQL Server Management Studio or the like to verify that it works. Once you do verify it (it should work assuming your table structure is what I think it is) then figure out what your code is doing wrong.
Update: I am laughing here as my answer is "correcting" lots of other answers that are disappearing as it becomes obvious that they are not right.

You should wrap this up into a stored procedure because logically it's one unit of work - and you may want to call it from more than one location too.
I would also seriously consider whether you should wrap the two statements up into a transaction - you wouldn't want the insert into students succeeding and that into records failing. OK that's an edge condition but it's easy to guard against in a SP and makes more professional code.
Another advantage of using an SP in this case is that as you're actioning a couple of inserts already it's quite possible that you'll want to extend this later - insert into a finance table for example. If you wrap up into an SP you can just alter the SP rather than have to grep code for all instances of a new student insert, amend and recompile.

You need to create a Stored Procedure that contains those SQL statements, and then execute the Stored Procedure from your C# code.

Related

What is the correct sql syntax to delete?

I'm making a simple board. I want to delete an article to connect in DB one access after the user has input password.
So, I made a method in a DAO class. This is the query part.
sql.append("DELETE FROM article ");
sql.append("WHERE ? = (SELECT pwd FROM article WHERE no = ?) and no = ?");
pstmt = conn.prepareStatement(sql.toString());
pstmt.setString(1, pwd);
pstmt.setInt(2, no);
pstmt.setInt(3, no);
Someone told me it is incorrect syntax. But, it is working.
Is it incorrect syntax?
Q: Is it incorrect syntax?
The syntax of the SQL DELETE statement looks valid. There's nothing "incorrect" about the syntax, in terms of it being a valid SQL statement to prepare and execute.
However, it does look like the subquery is not necessary. I believe an equivalent result could be achieved without a subquery. We would tend to write a simpler statement, without the subquery. But that doesn't make the syntax of your statement "incorrect".
What we don't see is the reasoning for including the subquery. Why wouldn't this statement achieve an equivalent result?
DELETE FROM article WHERE pwd = ? AND no = ?
Most (all?) relational databases are going to throw an error if (when) the subquery returns more than one row. (We don't see any guarantee that no is unique in the article table.)
If the value in the pwd column is NULL, then the equality comparison "pwd = ?" in the WHERE clause is going to evaluate to NULL. So it's not possible for this statement to delete a row that has a NULL value for pwd. (The statement would need to be modified to allow deletion of rows with NULL values for pwd column.)
We don't see any Java code that initializes sql. We're going to assume that there's a previous line that sets the contents of sql to a zero length string, or whitespace and/or valid SQL comment. Why not just
sql = "DELETE FROM article"
+ " WHERE pwd = ?"
+ " AND no = ?";
On a style note, when I'm dynamically generating a statement, appending additional SQL syntax to an existing string, I tend to include the whitespace at the beginning of the string I'm adding, not at the end of what I'm going to add to.
If the pwd column is a "password", we're assuming that what's being stored is a hashed value, and not plaintext.
And we're assuming that this block is within a "try/catch/finally" block.
We can have some quibbles with the code.
But as far as the syntax of the SQL DELETE statement, it looks valid to me.
I think you have unnecessary subqueries in your statement. Why don't you simplify your query:
sql.append("DELETE FROM article WHERE no = ?");
pstmt = conn.prepareStatement(sql.toString());
pstmt.setInt(1, no);

Execute multiple stored procedures in one transaction from WCF

This is my first post on here..
I'm writing a program in MVC3 that has a WCF service which acts as the Data Access Layer. In my DAL, I have to do some sort of 'batch' inserts and updates.. particularly with orders for example.. let's say one order has several items and could have several payment methods etc.. so when I insert a new order I'll need to insert all items related to that order and so on..
Therefore, what I'm looking for is the better way and feasible method to be able to run several stored procedures, e.g one which will insert the order, another which will insert its items, etc..
The tables Order and Item are linked together with a third table called Order_Items, which will have (fk) order_id, (fk) item_id, qty, price..
I know I can run multiple commands by changing command text and and executing non query withing a transaction.. but I would like to run stored procedures instead of hardcoding text commands.. or I can run the procedures by making command text something like
cmd.CommandText = 'exec sp_insert_order #order_number #order_date ...'
cmd.ExecuteNonQuery();
and then loop the items say
foreach (string s in insert_items)
{
cmd.CommandText = s;
cmd.ExecuteNonQuery();
}
all this within a transaction and then do a commit.. but I don't feel this is such a clean way of doing things.. can someone please share their opinion.
If you're using stored procedure, you should change the way you call them - I would recommend using this approach:
// define your stored procedure name, and the type
cmd.CommandText = 'dbo.sp_insert_order';
cmd.CommandType = CommandType.StoredProcedure;
// define and fill your parameters
cmd.Parameters.Add("#order_number", SqlDbType.Int).Value = order_nr;
cmd.Parameters.Add("#order_date", SqlDbType.DateTime).Value = ......;
cmd.ExecuteNonQuery();
Basically, you'd have to do this for each stored procedure you want to call, and you could wrap all of those in a single transaction without any problems:
using(SqlConnection connection = new SqlConnection("your-connection-string-here"))
{
SqlTransaction transaction = connection.BeginTransaction();
try
{
// call all stored procuedures here - remember to assign the
// transaction to the SqlCommand!!
....
transaction.Commit();
}
catch(Exception exc)
{
transaction.Rollback();
}
}
You can use the TransactionScope attributes on your methods to enclose all work in a transaction proc or text
You may also be interested in the Transaction Propagation functionality built in to WCF. It can be configured in such a way that each web service call to WCF automatically creates, and commits or rolls-back transactions for you, basically wrapping the entire service method call in a transaction.
There is a good MSDN writeup on it here.
It is a bit of an advanced topic and may be overkill for what you need, but something to keep in mind.

How can prepared statements protect from SQL injection attacks?

How do prepared statements help us prevent SQL injection attacks?
Wikipedia says:
Prepared statements are resilient against SQL injection, because
parameter values, which are transmitted later using a different
protocol, need not be correctly escaped. If the original statement
template is not derived from external input, SQL injection cannot
occur.
I cannot see the reason very well. What would be a simple explanation in an easy English and some examples?
The idea is very simple - the query and the data are sent to the database server separately.
That's all.
The root of the SQL injection problem is in the mixing of the code and the data.
In fact, our SQL query is a legitimate program.
And we are creating such a program dynamically, adding some data on the fly. Thus, the data may interfere with the program code and even alter it, as every SQL injection example shows it (all examples in PHP/Mysql):
$expected_data = 1;
$query = "SELECT * FROM users where id=$expected_data";
will produce a regular query
SELECT * FROM users where id=1
while this code
$spoiled_data = "1; DROP TABLE users;"
$query = "SELECT * FROM users where id=$spoiled_data";
will produce a malicious sequence
SELECT * FROM users where id=1; DROP TABLE users;
It works because we are adding the data directly to the program body and it becomes a part of the program, so the data may alter the program, and depending on the data passed, we will either have a regular output or a table users deleted.
While in case of prepared statements we don't alter our program, it remains intact
That's the point.
We are sending a program to the server first
$db->prepare("SELECT * FROM users where id=?");
where the data is substituted by some variable called a parameter or a placeholder.
Note that exactly the same query is sent to the server, without any data in it! And then we're sending the data with the second request, essentially separated from the query itself:
$db->execute($data);
so it can't alter our program and do any harm.
Quite simple - isn't it?
The only thing I have to add that always omitted in the every manual:
Prepared statements can protect only data literals, but cannot be used with any other query part.
So, once we have to add, say, a dynamical identifier - a field name, for example - prepared statements can't help us. I've explained the matter recently, so I won't repeat myself.
Here is an SQL statement for setting up an example:
CREATE TABLE employee(name varchar, paymentType varchar, amount bigint);
INSERT INTO employee VALUES('Aaron', 'salary', 100);
INSERT INTO employee VALUES('Aaron', 'bonus', 50);
INSERT INTO employee VALUES('Bob', 'salary', 50);
INSERT INTO employee VALUES('Bob', 'bonus', 0);
The Inject class is vulnerable to SQL injection. The query is dynamically pasted together with user input. The intent of the query was to show information about Bob. Either salary or bonus, based on user input. But the malicious user manipulates the input corrupting the query by tacking on the equivalent of an 'or true' to the where clause so that everything is returned, including the information about Aaron which was supposed to be hidden.
import java.sql.*;
public class Inject {
public static void main(String[] args) throws SQLException {
String url = "jdbc:postgresql://localhost/postgres?user=user&password=pwd";
Connection conn = DriverManager.getConnection(url);
Statement stmt = conn.createStatement();
String sql = "SELECT paymentType, amount FROM employee WHERE name = 'bob' AND paymentType='" + args[0] + "'";
System.out.println(sql);
ResultSet rs = stmt.executeQuery(sql);
while (rs.next()) {
System.out.println(rs.getString("paymentType") + " " + rs.getLong("amount"));
}
}
}
Running this, the first case is with normal usage, and the second with the malicious injection:
c:\temp>java Inject salary
SELECT paymentType, amount FROM employee WHERE name = 'bob' AND paymentType='salary'
salary 50
c:\temp>java Inject "salary' OR 'a'!='b"
SELECT paymentType, amount FROM employee WHERE name = 'bob' AND paymentType='salary' OR 'a'!='b'
salary 100
bonus 50
salary 50
bonus 0
You should not build your SQL statements with string concatenation of user input. Not only is it vulnerable to injection, but it has caching implications on the server as well (the statement changes, so less likely to get a SQL statement cache hit whereas the bind example is always running the same statement).
Here is an example of Binding to avoid this kind of injection:
import java.sql.*;
public class Bind {
public static void main(String[] args) throws SQLException {
String url = "jdbc:postgresql://localhost/postgres?user=postgres&password=postgres";
Connection conn = DriverManager.getConnection(url);
String sql = "SELECT paymentType, amount FROM employee WHERE name = 'bob' AND paymentType=?";
System.out.println(sql);
PreparedStatement stmt = conn.prepareStatement(sql);
stmt.setString(1, args[0]);
ResultSet rs = stmt.executeQuery();
while (rs.next()) {
System.out.println(rs.getString("paymentType") + " " + rs.getLong("amount"));
}
}
}
Running this with the same input as the previous example shows the malicious code does not work because there is no paymentType matching that string:
c:\temp>java Bind salary
SELECT paymentType, amount FROM employee WHERE name = 'bob' AND paymentType=?
salary 50
c:\temp>java Bind "salary' OR 'a'!='b"
SELECT paymentType, amount FROM employee WHERE name = 'bob' AND paymentType=?
Basically, with prepared statements the data coming in from a potential hacker is treated as data - and there's no way it can be intermixed with your application SQL and/or be interpreted as SQL (which can happen when data passed in is placed directly into your application SQL).
This is because prepared statements "prepare" the SQL query first to find an efficient query plan, and send the actual values that presumably come in from a form later - at that time the query is actually executed.
More great info here:
Prepared statements and SQL Injection
I read through the answers and still felt the need to stress the key point which illuminates the essence of Prepared Statements. Consider two ways to query one's database where user input is involved:
Naive Approach
One concatenates user input with some partial SQL string to generate a SQL statement. In this case the user can embed malicious SQL commands, which will then be sent to the database for execution.
String SQLString = "SELECT * FROM CUSTOMERS WHERE NAME='"+userInput+"'"
For example, malicious user input can lead to SQLString being equal to "SELECT * FROM CUSTOMERS WHERE NAME='James';DROP TABLE CUSTOMERS;'
Due to the malicious user, SQLString contains 2 statements, where the 2nd one ("DROP TABLE CUSTOMERS") will cause harm.
Prepared Statements
In this case, due to the separation of the query & data, the user input is never treated as a SQL statement, and thus is never executed. It is for this reason, that any malicious SQL code injected would cause no harm. So the "DROP TABLE CUSTOMERS" would never be executed in the case above.
In a nutshell, with prepared statements malicious code introduced via user input will not be executed!
When you create and send a prepared statement to the DBMS, it's stored as the SQL query for execution.
You later bind your data to the query such that the DBMS uses that data as the query parameters for execution (parameterization). The DBMS doesn't use the data you bind as a supplemental to the already compiled SQL query; it's simply the data.
This means it's fundamentally impossible to perform SQL injection using prepared statements. The very nature of prepared statements and their relationship with the DBMS prevents this.
In SQL Server, using a prepared statement is definitely injection-proof because the input parameters don't form the query. It means that the executed query is not a dynamic query.
Example of an SQL injection vulnerable statement.
string sqlquery = "select * from table where username='" + inputusername +"' and password='" + pass + "'";
Now if the value in the inoutusername variable is something like a' or 1=1 --, this query now becomes:
select * from table where username='a' or 1=1 -- and password=asda
And the rest is commented after --, so it never gets executed and bypassed as using the prepared statement example as below.
Sqlcommand command = new sqlcommand("select * from table where username = #userinput and password=#pass");
command.Parameters.Add(new SqlParameter("#userinput", 100));
command.Parameters.Add(new SqlParameter("#pass", 100));
command.prepare();
So in effect you cannot send another parameter in, thus avoiding SQL injection...
The key phrase is need not be correctly escaped. That means that you don't need to worry about people trying to throw in dashes, apostrophes, quotes, etc...
It is all handled for you.
ResultSet rs = statement.executeQuery("select * from foo where value = " + httpRequest.getParameter("filter");
Let’s assume you have that in a Servlet you right. If a malevolent person passed a bad value for 'filter' you might hack your database.
The simple example:
"select * from myTable where name = " + condition;
And if user input is:
'123'; delete from myTable; commit;
The query will be executed like this:
select * from myTable where name = '123'; delete from myTable; commit;
Root Cause #1 - The Delimiter Problem
Sql injection is possible because we use quotation marks to delimit strings and also to be parts of strings, making it impossible to interpret them sometimes. If we had delimiters that could not be used in string data, sql injection never would have happened. Solving the delimiter problem eliminates the sql injection problem. Structure queries do that.
Root Cause #2 - Human Nature, People are Crafty and Some Crafty People Are Malicious And All People Make Mistakes
The other root cause of sql injection is human nature. People, including programmers, make mistakes. When you make a mistake on a structured query, it does not make your system vulnerable to sql injection. If you are not using structured queries, mistakes can generate sql injection vulnerability.
How Structured Queries Resolve the Root Causes of SQL Injection
Structured Queries Solve The Delimiter Problem, by by putting sql commands in one statement and putting the data in a separate programming statement. Programming statements create the separation needed.
Structured queries help prevent human error from creating critical security holes.
With regard to humans making mistakes, sql injection cannot happen when structure queries are used. There are ways of preventing sql injection that don't involve structured queries, but normal human error in that approaches usually leads to at least some exposure to sql injection. Structured Queries are fail safe from sql injection. You can make all the mistakes in the world, almost, with structured queries, same as any other programming, but none that you can make can be turned into a ssstem taken over by sql injection. That is why people like to say this is the right way to prevent sql injection.
So, there you have it, the causes of sql injection and the nature structured queries that makes them impossible when they are used.

Insert data into database [Delphi]

I'm trying using a TAdoTable component,
On form Create I call .Append() and in a button i call .Post()
but it loads the entire table! I don't need it to load anything, just need to insert a row into this table.
I was wondering if there is "good way" of inserting data into database with Ado, i already tried using the a "manual" approach with TAdoCommand but it doesn't seems right to me
I generate the INSERT query using Format() and all string fields are escaped with QuotedStr()
Thanks in advance!
Arthur.
You can use a TADODataset (or TADOQuery).
The way I do it sometimes is with by setting the CommandText to return 0 records from the table, i.e. SELECT TOP 0 * FROM [table], then use .Append and .Post
But personally, I prefer writing the SQL, such as with a TADOCommand
Use the TADOQuery object if you don't need to display the table's data.
Basically:
Use TADOQuery.SQL.Text to set the SQL command
Use TADOQuery.ExecSQL method to fire the SQL command
You can also use the TADOCommand component, and have it execute the specific SQL command. If you find yourself performing the same command over and over again (like inserts into a table) then consider using parameters rather than directly changing the SQL for every call. Parameters are easy to use, just place a :PARAMNAME in your sql, then use the parameters object on the ado component your using to set the value. For example:
Assuming the CommandText of the TAdoCommand component contains "INSERT INTO TABLENAME (FIELD1) VALUES (:FIELDVALUE1)"
AdoCommand1.Parameters.ParamByName('FIELDVALUE1').Value := 'TEST'
AdoCommand1.Execute;
When the above sql is executed, then the string "TEST" would be written to FIELD1.
var
CountVar: Integer;
begin
TADOConnection1.Execute(ASQLInsertStatement, CountVar, [adExecuteNoRecords]);
end;

SQL Statement Not failing, but not inserting

ASP.NET 2.0, SQL 2005. I have a very basic insert statement. I enter all the data into the app and step through. No errors are rasied in the app or the stored proc. Yet, when I go to check out the table, no record was inserted. Is there some sort of quirk or bug in SQL server I am unaware of? I have tried ExecuteScalar & ExecuteNonQuery.
Can it be that you open a transaction and never Commit one? Remember that
using(var transaction = connection.BeginTransaction())
{
// Code
}
does not commit it, but rather rolls back the whole thing. You have to explicitly invoke transaction.Commit().
You need to commit your transaction.
I had (have) this problem on a website of mine written in PHP. If you are trying to insert a string are you sure you have escaped all necessary characters? Using a single quote in something like don't, won't, or aren't needs to be escaped!