Dynamic Linq failing when using Contains against Int Field - mysql

I'm using Entity Frameworks 4.1.0.0 and MySQL.Data.Entity 6.5.4.0 and when I try and generate a dynamic query for a range of integers, I get an error of:
No applicable method 'Contains' exists in type 'Int32'
This seems to work fine when using a similar structure to check against Strings..but I want to expand this to support the other db fields I have in my data.
Code Example:
int[] ids = new int[] { 1, 3, 4 };
IQueryable<entityname> list = db.tablename.Where("Id.Contains(#0)", ids);
I have added in the Dynamic.cs to my project and followed along with
http://blog.walteralmeida.com/2010/05/advanced-linq-dynamic-linq-library-add-support-for-contains-extension-.html
but there has been no difference then using the Dynamic I loaded via Nuget.
Thank you in advance.

The syntax is slightly different:
IQueryable<entityname> list = db.tablename.Where("#0.Contains(outerIt.Id)", ids);
following the link you refer to.

If you need to check if a given (variable) int value is contained within a entity column, you can do the following using Dynamic Linq:
return query.Where(String.Format("{0}.ToString().Contains(#0)", field), value);
Check out this answer for an extension method that can perform such task with strings, integers and booleans column types in a rather seamless way.

Related

Querying Unix Timestamp using JOOQ

I'm using a MySQL server, and I'm trying to retrieve a timestamp using the JOOQ API. However, I think the default JOOQ behavior returns the time in the local timezone, and not UTC (it's not using UNIX_TIMESTAMP(). Using JOOQ, my query looks like
db.select(USER_TABLE.REGISTERED_ON)
.from(USER_TABLE)
.where(USER_TABLE.EMAIL.equal(email)
.fetchAny()
However, the sql that I want to execute should be something like this
SELECT UNIX_TIMESTAMP(schema.table.timestamp_col)
FROM schema.table
WHERE email="someone#domain.com"
Is it possible using the JOOQ API? If not, what's the best way to run this query, because I really want to be able to use the generated code (USER_TABLE, USER_TABLE.REGISTERED_ON, etc).
EDIT: I'm now doing the following, but is it safe? Basically I'm removing the quotations from JOOQ's generated classes.
String timestamp_field = USER_TABLE.REGISTERED_ON.toString().replace("\"", "");
Field<?> f = DSL.field("UNIX_TIMESTAMP(" + timestamp_field + ")");
Record r = db.select(f)
.from(USER_TABLE)
.where(USER_TABLE.EMAIL.equal(email))
.fetchAny();
There are several ways to tackle this problem:
Use a Converter or Binding to convert the type
You can register a data type Converter or Binding in the source code generator. This way, the code generator will generate a Field<YourType> for every TIMESTAMP field in the database. Possible useful types are:
java.lang.Long
java.time.Instant
java.time.OffsetDateTime (note that jOOQ 3.7 will support this via [#4338])3
Use plain SQL
Use plain SQL every time you want to do an explicit conversion using the UNIX_TIMESTAMP() function. Your solution works:
String timestamp_field = USER_TABLE.REGISTERED_ON.toString().replace("\"", "");
Field<?> f = DSL.field("UNIX_TIMESTAMP(" + timestamp_field + ")");
But it is not recommended because:
You should never rely on any toString() implementation of any Java type.
You should generally try to avoid string concatenation with jOOQ's plain SQL API
A better solution would be:
DSL.field("UNIX_TIMESTAMP({0})", Long.class, USER_TABLE.REGISTERED_ON);
Or even:
public static Field<Long> unixTimestamp(Field<Timestamp> arg) {
return DSL.field("UNIX_TIMESTAMP({0})", Long.class, arg);
}
Use BIGINT in the database
You could of course use BIGINT or BIGINT UNSIGNED in the database instead of TIMESTAMP. This way, you will always automatically have the integer unix timestamp value. This is just a workaround for completeness's sake.

Why does MySQL permit non-exact matches in SELECT queries?

Here's the story. I'm testing doing some security testing (using zaproxy) of a Laravel (PHP framework) application running with a MySQL database as the primary store for data.
Zaproxy is reporting a possible SQL injection for a POST request URL with the following payload:
id[]=3-2&enabled[]=on
Basically, it's an AJAX request to turn on/turn off a particular feature in a list. Zaproxy is fuzzing the request: where the id value is 3-2, there should be an integer - the id of the item to update.
The problem is that this request is working. It should fail, but the code is actually updating the item where id = 3.
I'm doing things the way I'm supposed to: the model is retrieved using Eloquent's Model::find($id) method, passing in the id value from the request (which, after a bit of investigation, was determined to be the string "3-2"). AFAIK, the Eloquent library should be executing the query by binding the ID value to a parameter.
I tried executing the query using Laravel's DB class with the following code:
$result = DB::select("SELECT * FROM table WHERE id=?;", array("3-2"));
and got the row for id = 3.
Then I tried executing the following query against my MySQL database:
SELECT * FROM table WHERE id='3-2';
and it did retrieve the row where id = 3. I also tried it with another value: "3abc". It looks like any value prefixed with a number will retrieve a row.
So ultimately, this appears to be a problem with MySQL. As far as I'm concerned, if I ask for a row where id = '3-2' and there is no row with that exact ID value, then I want it to return an empty set of results.
I have two questions:
Is there a way to change this behaviour? It appears to be at the level of the database server, so is there anything in the database server configuration to prevent this kind of thing?
This looks like a serious security issue to me. Zaproxy is able to inject some arbitrary value and make changes to my database. Admittedly, this is a fairly minor issue for my application, and the (probably) only values that would work will be values prefixed with a number, but still...
SELECT * FROM table WHERE id= ? AND ? REGEXP "^[0-9]$";
This will be faster than what I suggested in the comments above.
Edit: Ah, I see you can't change the query. Then it is confirmed, you must sanitize the inputs in code. Another very poor and dirty option, if you are in an odd situation where you can't change query but can change database, is to change the id field to [VAR]CHAR.
I believe this is due to MySQL automatically converting your strings into numbers when comparing against a numeric data type.
https://dev.mysql.com/doc/refman/5.1/en/type-conversion.html
mysql> SELECT 1 > '6x';
-> 0
mysql> SELECT 7 > '6x';
-> 1
mysql> SELECT 0 > 'x6';
-> 0
mysql> SELECT 0 = 'x6';
-> 1
You want to really just put armor around MySQL to prevent such a string from being compared. Maybe switch to a different SQL server.
Without re-writing a bunch of code then in all honesty the correct answer is
This is a non-issue
Zaproxy even states that it's possibly a SQL injection attack, meaning that it does not know! It never said "umm yeah we deleted tables by passing x-y-and-z to your query"
// if this is legal and returns results
$result = DB::select("SELECT * FROM table WHERE id=?;", array("3"));
// then why is it an issue for this
$result = DB::select("SELECT * FROM table WHERE id=?;", array("3-2"));
// to be interpreted as
$result = DB::select("SELECT * FROM table WHERE id=?;", array("3"));
You are parameterizing your queries so Zaproxy is off it's rocker.
Here's what I wound up doing:
First, I suspect that my expectations were a little unreasonable. I was expecting that if I used parameterized queries, I wouldn't need to sanitize my inputs. This is clearly not the case. While parameterized queries eliminate some of the most pernicious SQL injection attacks, this example shows that there is still a need to examine your inputs and make sure you're getting the right stuff from the user.
So, with that said... I decided to write some code to make checking ID values easier. I added the following trait to my application:
trait IDValidationTrait
{
/**
* Check the ID value to see if it's valid
*
* This is an abstract function because it will be defined differently
* for different models. Some models have IDs which are strings,
* others have integer IDs
*/
abstract public static function isValidID($id);
/**
* Check the ID value & fail (throw an exception) if it is not valid
*/
public static function validIDOrFail($id)
{
...
}
/**
* Find a model only if the ID matches EXACTLY
*/
public static function findExactID($id)
{
...
}
/**
* Find a model only if the ID matches EXACTLY or throw an exception
*/
public static function findExactIDOrFail($id)
{
...
}
}
Thus, whenever I would normally use the find() method on my model class to retrieve a model, instead I use either findExactID() or findExactIDOrFail(), depending on how I want to handle the error.
Thank you to everyone who commented - you helped me to focus my thinking and to understand better what was going on.

cakephp 1.3 : how to omit virtual fields from a find query

I'm trying to convert the output of a Model->find query into SQL to be input into a database completely separate from the current MySQL database being used by the cakePHP system. My problem is that I have several virtual fields in the models which are inevitably returned when performing a Model->find on the data. Clearly, I need to find and remove these virtual fields from the find if I am to convert the data into SQL, which will be used as input to an identical database as the original MySQL one. Is there a simple way to omit virtual fields? any way that this can be done in a version higher than 1.3 would also be very helpful.
Many thanks.
You can either only define your virtual fiels at runtime. This is what I usually do.
$this->virtualFields['x'] = 'y';
// find query
But you can also limit the find fields
'fields' => array('all fields without the virtual fields')
This will also skip your virtual fields.
Usually you don't want to verbosely define all fields, though.
You can also unset all the virtual fields for the find() call:
$tmp = $this->virtualFields;
$this->virtualFields = array();
// find query
$this->virtualFields = $tmp;

Is there a way to avoid wasNull() method?

I have a big ResultSet (getting from a JDBC query) of few thousand rows. Using each of these rows, I have to instantiate an Object, setting fields of it according to the fields of this result set. Now, as we all know, the getXXX() methods of this JDBC API return 0 if that particular column was null. So for each field of each row, I have to do a wasNull() before setting the value in my object, which looks pretty ugly and may be is not efficient as well. So, is there any other way by which I can avoid it?
Apart from JDBC, if there is some entirely different, standard, commonly used way, I am open to know about that as well.
Thanks!
EDIT 1
patientInput.setRaceCodeId(patients.getShort("race_code_id"));
if(patients.wasNull())
patientInput.setRaceCodeId(null);
patients is a ResultSet. patientInput is an object. This is the code which I am trying to avoid. I mean, everytime I do a getXXX(), and do a setXXX(), I have to check again that what I got from ResultSet was not null. If it was, then set that object field as null, as getXXX() returns 0 in that case.
Ok. I believe there are two possible approaches to 'tidying' up your code. However, this could come down to a difference of opinion as to what is tidy!
Solution 1 - replace getXXX() with getObject() which returns null e.g.
Short s = (Short)patients.getObject("race_code_id");
patientInput.setRaceCodeId(s);
Solution 2 - write a generic wrapper method that retrieves nullable values
protected final <T> T getNullableValue(T returnType, String colName, ResultSet rs) throws SQLException {
Object colValue = rs.getObject(colName);
return (T) colValue;
}
final static Integer INT = 0;
final static Short SHORT = 0;
.
.
.
patientInput.setRaceCodeId(getNullableValue(SHORT,"race_code_id",patients));
You don't have to do it to each field, only to fields that are numeric and, possibly, boolean, and are declared as nullable in your database. It happens not as frequently as you fear.
If you absolutely hate writing such code, you can try switching to an ORM library, for example, Hibernate.

LINQ to SQL, how to write a method which checks if a row exists when we have multiple tables

I'm trying to write a method in C# which can take as parameter a tabletype, column and a columnvalue and check if the got a row with a with value
the method looks like:
public object GetRecordFromDatabase(Type tabletype, string columnname, string columnvalue)
I'm using LINQ to SQL and need to to this in a generic way so I don't need to write each table I got in the DB.
I have been doing this so far for each table, but with more than 70 of these it becomes cumbersome and boring to do.
Is there a way to generate the following code dynamically, And swap out the hardcoded tablenames with the values from the parameterlist? In this example I have a table in the DB named tbl_nation, which the DataContext pluralizes to tbl_nations, and I'm checking the column for the value
if (DB.tbl_nations.Count(c => c.code.Equals(columnvalue)) == 1)
{
return DB.tbl_nations.Single(c => c.code.Equals(columnvalue));
}
Take a look at System.Linq.Dynamic:
http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx