#usersfound = User.find_by_sql(["
SELECT * from users where name ## plainto_tsquery('english', ?) LIMIT 20 offset ?
",#query,#offset])
See above, is this safe from sql injection? I am very new to doing direct sql commands on a database in rails. (I am aware there may be other ways of doing this SPECIFIC query, but I am wondering if in general, using find_by_sql and that kind of insertion of vars is safe - I have some difficult queries with subselects and joins that are really possible to do with ActiveRecord.
Thanks.
Yes, that should be safe. If you trace through the code you'll find that your find_by_sql call ends up calling PGconn#send_query_prepared with the bind parameters being carried along as little more than baggage; the send_query_prepared method is just a wrapper for the PQsendQueryPrepared API call in libpq:
static VALUE
pgconn_send_query_prepared(int argc, VALUE *argv, VALUE self)
{
/* ... bunch of boiler plate marshalling stuff ... */
result = PQsendQueryPrepared(conn, StringValuePtr(name), nParams,
(const char * const *)paramValues, paramLengths, paramFormats,
resultFormat);
/* ... */
}
The bind parameters end up in paramValues. So you should be fine unless there are bugs in PostgreSQL's C library prepared statement handling.
Inserting dynamic values into a query using query parameters is safe.
But it depends on whether Rails is "faking" query parameters, and is actually combining #query and #offset into the SQL string before preparing the statement. Then it's only as safe as the implementation of escaping in Rails.
Related
I'm using TransactSQL.ScriptDom to parse SQL statements. I have rules defined where I want to find a) IF statements and b) UPDATE statements. When I'm looking through non-dynamic SQL, the rules work just fine. However, when I'm looking through dynamic SQL, my code only detects the IF blocks; it does not detect the UPDATE statements.
For instance, this code gets hit in a debugger in both the non-dynamic and dynamic scenarios:
public override void Visit(IfStatement ifStatement)
{
...
}
However, this code does not get hit in any dynamic SQL scenario, and I've also tried using UpdateSpecification:
public override void Visit(UpdateStatement updateStatement)
{
...
}
Now, if I change the code to Visit(TSqlFragment test), the code will get hit, but I only see a node of type AsciiStringLiteral for my UPDATE statement. Is there a better way to get my code to visit an UPDATE statement?
Disregard, this was user error. I had a type-o in my dynamic SQL where I was incorrectly using single-quotes. In other words, I was using this:
#"EXEC('UPDATE dbo.MyTable
SET MyColumn = 'MyValue';');",
... instead of this:
#"EXEC('UPDATE dbo.MyTable
SET MyColumn = ''MyValue'';');",
(I considered deleting this question altogether, but I'll leave it up in case it helps others.)
We have a search routine that uses criteria to build SQL query (because its restrictions added dynamically).
In a particular case (a very complicated case) we need to search over a table-valued function.(our model object is mapped to the function).
The result would be something like this :
SELECT count(*) FROM dbo.GetSubStaffsLetterInstances(#staffId) WHERE LetterNumber="1234";
The problem is I don't know how to pass #staffId to my criteria(I tried adding an Eq restrictions without success since restrictions are working on properties)
I know I can add a parameter to an IQuery but I don't know how I can do it using an ICriteria object.
If I understand your question completely, you can resort back to standard SQL:-
var sql = "SELECT count(*) FROM dbo.GetSubStaffsLetterInstances(:staffId)
WHERE LetterNumber=:letterNum";
var count = session.CreateSqlQuery(sql)
.setInt32("staffId", 12345)
.setString("letternum", "A1")
.UniqueResult<int>();
or try .UniqueResult<long>(); as I can't remember which one HQL returns
This is probably fairly straightforward but i can't seem to find a reasonable explanation in any documentation.
I'm trying to use an NHibernate.ISQLQuery and using SetResultTransformer() to return a custom set of results from a custom SQL query. Like so:
public virtual IList<T> GetSQLObject<T>(string sql, IDbParameter[] parameters = null)
{
ISQLQuery qry = _sess.CreateSQLQuery(sql);
qry.SetResultTransformer(Transformers.AliasToBean(typeof(T)));
if (parameters != null) {
foreach (IDbParameter parameter in parameters) {
qry.SetParameter(parameter.Name, parameter.Value);
}
}
return qry.List<T>();
}
From looking at the examples, it seems that in the sql query I have to use parameters in the format :param1 instead of #param1 as I would in a standard SQL query. If i use the latter syntax in the query, it throws an error at qry.SetParameter().
Is there a reason why ISQLQuery/NHibernate requires them in this format and won't work with the normal syntax?
SQL Server uses #param, but not every other database does. For example, MySQL uses ?param
NHibernate allows you to swap out 1 database implementation for another with little to no reworking of your DAL. It sets the parameters based on the database you configured when you setup the NH Configuration.
Edit: Also I think :param came about from Hibernate being targeted at Oracle when it was initially developed, since Oracle uses :param
Phil has answered the "why"; so perhaps I can recommend a "how"; why not just add a new extension method to the IDbParameter type (something like .GetNHibernateName() ) that will return the parameter name with the "#" replaced with a ":"; that should be trivial to implement.
I am doing some plain SQLs in my rails model (for purists this is just for complex SQLs :)
Since I am not using find*/condition methods, is there a helper method that I can use straight to do that?
The quote method on the connection object escapes strings. When building up queries, use sanitize_sql_for_conditions to convert ActiveRecord conditions hashes or arrays to SQL WHERE clauses.
The methods in ActiveRecord::ConnectionAdapters::DatabaseStatements are handy for direct queries, in particular the ones starting with select_.
Rails uses sanitize_sql_for_conditions internally for dealing with placeholders. Of course, that method is protected so you can't (cleanly) use it outside of an ActiveRecord model. You can get around the protectedness using send:
escaped_string = Model.send(:sanitize_sql_for_conditions, [
'id = ? and name = ?',
params[:id], params[:name]
]
)
Will hql give you compile time errors like criteria query?
I remember hearing that one of the methods doesn't (besides raw SQL).
The short answer is no. Since HQL is essentially a string, you need an IDE to parse it and figure out if you're doing something wrong.
No query build in Hibernate, neither HQLs nor Critieras, will produce compile time errors. Nevertheless you can use the NamedQuery annotation to declare your static HQL queries in a static way. This will provide caching and validity checks when starting your application because hibernate's session factory will read all NamedQueries on first startup.
HQL wil not give you compile time errors, as it is only treated as a string at compile time.
What do you mean with 'like criteria query'?
Criteria queries may not give you compile time errors, something like this will error
ICriteria crit = sess.CreateCriteria(typeof(Cat));
crit.SetMaxResults("50"); /* wrong parameter type */
List cats = crit.List();
Something like this will not
IList cats = sess.CreateCriteria(typeof(Cat))
.Add( Expression.Like("Naem", "Fritz%") ) /* misspelled property */
.Add( Expression.Between("Weight", minWeight, maxWeight) )
.List();