Convert SQL statement to Hibernate Criteria or Projections - sql

I'd like to convert this SQL Statement into either Criteria or Projections. I'm sorry I don't know which one to use since I'm new to Hibernate. I've done some research, and it looks like both are needed to achieve what I wanted.
Before I always use SQL Statements in my programs but when I saw a sample code which allows you to create queries without writing SQL Statements by using Criteria, I wanted to use it since it gives me cleaner code.
Thanks in advance.
String query = "SELECT MAX(employeeNo) "
+ "FROM Profile "
+ "WHERE SUBSTRING(employeeNo,1,2)='" + yy + "'";
empNo = session.createQuery(query).list().get(0).toString();
This query gets the highest employee number in the database for a given year yy.
Sample result would be 14-229

This is assuming that you've already defined a mapping for Profile entity.
Session session = sessionFactory.getCurrentSession();
String empNo = (String) session
.createCriteria(Profile.class)
.add(Restrictions.sqlRestriction("substring(employeeNo,1,2) = ?", yy, StringType.INSTANCE)
.setProjection(Projections.max("employeeNo"))
.uniqueResult();
Now, this I don't know if I'd agree with your statement that this is cleaner. The nice thing about using Criteria is the allow you to build a criteria dynamically, but it's very verbose, and it isn't clear exactly what you are trying to do at first glance. Plus, because of the substring function, forces you to mix in a sqlRestriction. Instead, you could use HQL:
Session session = sessionFactory.getCurrentSession();
String empNo = (String) session.createQuery("SELECT MAX(employeeNo) FROM Profile WHERE substring(employeeNo,1,2) = :year")
.setString("year", yy)
.uniqueResult();
Personally, I think the HQL or even SQL approach is a little cleaner, and expresses intent better.

Related

Filtering Harmful SQL Select Statements in ASP.NET

I am exposing a web service that constructs a SQL SELECT statement and accepts parameters from a controller. The generic functions looks like this:
DataTable SqlSelect (string select, string from, string Where, string orderby = "", string groupBy = "")
{
string sql = "SELECT " + select + " FROM " + from + " WHERE " + where
(orderby =="") ? "" : "ORDER BY " + orderby ...
//do other stuff
}
Now what makes me worry is the fact that base on given function above, the user may now inject harmful commands like:
SqlSelect("DROP TABLE 'TABLENAME'", "INFORMATION_SCHEMA.TABLES", "TABLE_NAME like %%'");
Which I want to prevent.
Now my question is: what is the best thing I can do to prevent user to UPDATE, MODIFY, DELETE, TRUNCATE tables and only allow SELECT statement (can use something like READ oNLY?)
Note: this is similar to this question but the user was working on PHP, while I'm in ASP.NET MVC, also what I want to achieve here is only allow SELECT or 'GET' statement.
Do not do it this way. You need to parameterize your queries which means that you cannot accept SQL text as an input. I have found many attempts by developers to detect SQL injection attacks and I almost always find a way of getting past their logic.
If you need to be able to dynamically construct any SELECT query based on any table in your database then you could easily create a class that indicates the table, select columns and where predicate columns as enums, and the values of the where predicates. Concatenate the SQL text based on this class and include the predicate values using SqlParameters.
It is just one example, but for sure you do not want to accept SQL text.
Make use of a data reader https://msdn.microsoft.com/en-us/library/haa3afyz(v=vs.110).aspx. You can catch any exceptions when you call ExecuteReader().
However I would advise against exposing this kind of generic functionality to client side code. You should rather only provide controlled access to your data via an appropriate data layer using something like the repository pattern.

SQL Injection: Why is the following code dangerous?

An intern has written the following vb.net code:
Public Sub PopulateUsersByName (name As String)
'Here, the parameter 'name' is unsantized, coming straight from the form
Dim query As String = ""
query += vbNewLine + " SELECT Id, FirstName, LastName FROM dbo.[Users]"
query += vbNewLine + " WHERE FirstName LIKE '" + REPLACE(name, "'", "''") + "'"
query += vbNewLine + " OR LastName LIKE '" + REPLACE(name, "'", "''") + "'"
'Execute SQLCommand with above query and no parameters
'Then do some other stuff
END Sub
I have explained that in general, one should never use string concatenation when trying to do something like the above. The best practice is to use either an SP, or an SQLClient.SQLCommand with parameters.
His logic is: any sql varchar(xxx) gets sanitized by replacing all single quotes with two single quotes (and adding additional single quotes at the start and end of the string).
I am unable to provide an example of something the user could type that would get around this - I'm hoping I can find something more convincing than "But, as a general principal, one should avoid this - you know... coz... well, don't argue with me - I'M THE BOSS AND MY WISH IS YOUR COMMAND.".
Note: The code will always connect to our Microsoft SQL Server. But I can imagine it failing to sanitize the input on some other SQL Implementation.
UPDATE:
Just to make it a little clearer, what I'm looking for is a possible value of the parameter name which will allow someone to inject SQL into the query.
Try this with his code using '%_%' (with and without the single quotes) as the input....same as this in SQL....
select SELECT Id, FirstName, LastName FROM dbo.[Users] from TBL_EMPLOYEES where FirstName like '%_%' or LastName like '%_%'
irrespective if it failing or not, his is very poor code... fair enough this one is only a one liner, but anything more than that, including complicated SQL statements would be difficult to maintain and debug.. in any case, using Sps gets him used to using them AND allows him to take advantage of the flexibility and power of T-SQL... LOL, i'd dread to think how some of the SQL I have written would look like in code.....
You know, I come across code like this (and a lot worse) all the time... just because it might work for a while DOESN'T mean it's the right way to do it.... If your intern that does NOT listen to experience he will NEVER make a good developer and that is sadly a fact
I once reduced a junior developers attempt at importing a CSV file (50 million rows) in the same way your intern has done, from her 300 lines of code (which was never going to work) to just one line of LINQ to convert it to XML (we couldn't use Bulk Insert or bcp) and a fancy SP... Was bullet proof, job done....
I can get a list of all your users. If name = %%
Now I know the full name of everyone in your database.
I would consider that a security hole.
Sanitizing is not the answer. You can by pass quotes and use "smuggling". A good example is http://danuxx.blogspot.com.br/2011/08/sql-injection-bypassing-single-quotes.html
Also a good practice (to use dynamic queries) is to use parametric dynamic queries. Also SPs can do the trick (if you don't use dynamic queries inside it off course).

NHibernate - define where condition

In my application the user can defines search-conditions. He can choose a column, set an operator (equals, like, greater than, less or equal than, etc.) and give in the value. After the user clicks on a button and the application should do a search on the database with the condition. I use NHibernate and ask me now, what is the efficientest way to do this with NHibernate.
Should I create a query with it like (Column=Name, Operator=Like, Value=%John%)
var a = session.CreateCriteria<Customer>();
a.Add(Restrictions.Like("Name", "%John%"));
return a.List<Customer>();
Or should I do this with HQL:
var q = session.CreateQuery("from Customer where " + where);
return q.List<Customer >();
Or is there a more bether solution?
Thanks for your help.
Best Regards, Thomas
You can use either one of them. There might be hardly an differences between the two. But whatever you do make sure that your column names are in constants or are mapped to the column name otherwise your repository will be tightly coupled to your model definition i.e if you update the columnname you will have to go and update these statements yourself.
And when you are building the where clause makes ure you have a function that appends the right query. you will probably be having a switch case statement for the same.
In term of efficence there is no difference. In the HQL version I would prefer use a parameter instead of adding the where part as a string.
If you are using NH3.0 you can consider using QueryOver too, to avoid using string to describe your properties

vb.net handling many table name using string

Am storing a table name in a String
ugad = "INSERT INTO tb(Ugname,Ugdob,Uggender)"
this is the ordinary query which functions well.
But i need to store a Tablename in a string called "dept"
and this string will have diff table name at diff times. How should i run it, Wat query should I Give.
ugad = "INSERT INTO dept(Ugname,Ugdob,Uggender)"
I know this query is not vaild. May i know the correct query
Use:
ugad = "INSERT INTO " & dept & "(Ugname,Ugdob,Uggender)"
N.B. There are arguably safer, better ways to compose SQL (if you are worried about malicious or accidental interference with your underlying data through SQL injection) than the above but hopefully that gets you started.
Or
ugad = String.Format("INSERT INTO {0}(Ugname,Ugdob,Uggender)", dept)
Which I think is easier to read and easier to maintain.
If I understand you correctly you neet to try something like
ugad = "INSERT INTO " + dept + "(Ugname,Ugdob,Uggender)"
Have a llok at Operators in VB.NET
Just remember that string concatenation can be very slow once you start concatenating in loops, so always have in the back of your mind that the StringBuilder Class exists, and is a lot faster than normal concatenation...

How bad is my query?

Ok I need to build a query based on some user input to filter the results.
The query basically goes something like this:
SELECT * FROM my_table ORDER BY ordering_fld;
There are four text boxes in which users can choose to filter the data, meaning I'd have to dynamically build a "WHERE" clause into it for the first filter used and then "AND" clauses for each subsequent filter entered.
Because I'm too lazy to do this, I've just made every filter an "AND" clause and put a "WHERE 1" clause in the query by default.
So now I have:
SELECT * FROM my_table WHERE 1 {AND filters} ORDER BY ordering_fld;
So my question is, have I done something that will adversely affect the performance of my query or buggered anything else up in any way I should be remotely worried about?
MySQL will optimize your 1 away.
I just ran this query on my test database:
EXPLAIN EXTENDED
SELECT *
FROM t_source
WHERE 1 AND id < 100
and it gave me the following description:
select `test`.`t_source`.`id` AS `id`,`test`.`t_source`.`value` AS `value`,`test`.`t_source`.`val` AS `val`,`test`.`t_source`.`nid` AS `nid` from `test`.`t_source` where (`test`.`t_source`.`id` < 100)
As you can see, no 1 at all.
The documentation on WHERE clause optimization in MySQL mentions this:
Constant folding:
(a<b AND b=c) AND a=5
-> b>5 AND b=c AND a=5
Constant condition removal (needed because of constant folding):
(B>=5 AND B=5) OR (B=6 AND 5=5) OR (B=7 AND 5=6)
-> B=5 OR B=6
Note 5 = 5 and 5 = 6 parts in the example above.
You can EXPLAIN your query:
http://dev.mysql.com/doc/refman/5.0/en/explain.html
and see if it does anything differently, which I doubt. I would use 1=1, just so it is more clear.
You might want to add LIMIT 1000 or something, when no parameters are used and the table gets large, will you really want to return everything?
WHERE 1 is a constant, deterministic expression which will be "optimized out" by any decent DB engine.
If there is a good way in your chosen language to avoid building SQL yourself, use that instead. I like Python and Django, and the Django ORM makes it very easy to filter results based on user input.
If you are committed to building the SQL yourself, be sure to sanitize user inputs against SQL injection, and try to encapsulate SQL building in a separate module from your filter logic.
Also, query performance should not be your concern until it becomes a problem, which it probably won't until you have thousands or millions of rows. And when it does come time to optimize, adding a few indexes on columns used for WHERE and JOIN goes a long way.
TO improve performance, use column indexes on fields listen in "WHERE"
Standard SQL Injection Disclaimers here...
One thing you could do, to avoid SQL injection since you know it's only four parameters is use a stored procedure where you pass values for the fields or NULL. I am not sure of mySQL stored proc syntax, but the query would boil down to
SELECT *
FROM my_table
WHERE Field1 = ISNULL(#Field1, Field1)
AND Field2 = ISNULL(#Field2, Field2)
...
ORDRE BY ordering_fld
We've been doing something similiar not too long ago and there're a few things that we observed:
Setting up the indexes on the columns we were (possibly) filtering, improved performance
The WHERE 1 part can be left out completely if the filters're not used. (not sure if it applies to your case) Doesn't make a difference, but 'feels' right.
SQL injection shouldn't be forgotten
Also, if you 'only' have 4 filters, you could build up a stored procedure and pass in null values and check for them. (just like n8wrl suggested in the meantime)
That will work - some considerations:
About dynamically built SQL in general, some databases (Oracle at least) will cache execution plans for queries, so if you end up running the same query many times it won't have to completely start over from scratch. If you use dynamically built SQL, you are creating a different query each time so to the database it will look like 100 different queries instead of 100 runs of the same query.
You'd probably just need to measure the performance to find out if it works well enough for you.
Do you need all the columns? Explicitly specifying them is probably better than using * anyways because:
You can visually see what columns are being returned
If you add or remove columns to the table later, they won't change your interface
Not bad, i didn't know this snippet to get rid of the 'is it the first filter 3' question.
Tho you should be ashamed of your code ( ^^ ), it doesn't do anything to performance as any DB Engine will optimize it.
The only reason I've used WHERE 1 = 1 is for dynamic SQL; it's a hack to make appending WHERE clauses easier by using AND .... It is not something I would include in my SQL otherwise - it does nothing to affect the query overall because it always evaluates as being true and does not hit the table(s) involved so there aren't any index lookups or table scans based on it.
I can't speak to how MySQL handles optional criteria, but I know that using the following:
WHERE (#param IS NULL OR t.column = #param)
...is the typical way of handling optional parameters. COALESCE and ISNULL are not ideal because the query is still utilizing indexes (or worse, table scans) based on a sentinel value. The example I provided won't hit the table unless a value has been provided.
That said, my experience with Oracle (9i, 10g) has shown that it doesn't handle [ WHERE (#param IS NULL OR t.column = #param) ] very well. I saw a huge performance gain by converting the SQL to be dynamic, and used CONTEXT variables to determine what to add. My impression of SQL Server 2005 is that these are handled better.
I have usually done something like this:
for(int i=0; i<numConditions; i++) {
sql += (i == 0 ? "WHERE " : "AND ");
sql += dbFieldNames[i] + " = " + safeVariableValues[i];
}
Makes the generated query a little cleaner.
One alternative i sometimes use is to build the where clause an an array and then join them together:
my #wherefields;
foreach $c (#conditionfields) {
push #wherefields, "$c = ?",
}
my $sql = "select * from table";
if(#wherefields) { $sql.=" WHERE " . join (" AND ", #wherefields); }
The above is written in perl, but most languages have some kind of join funciton.