How to escape "?" in Expression.Sql in NHibernate (C#) - nhibernate

When i'm trying to use Postgresql '?' operator within Expression.Sql
it thinks i'm trying to add a new parameter, and fails.
Example:
Expression.Sql("(this_.data -> 'glossary' ->> 'GlossDiv')::jsonb ? ?", "testValue", NHibernateUtil.String);
[ADOExceptionReporter]: Index was out of range. Must be non-negative and less than the size of the collection.
How to escape it ?

Can you try overload using SqlString as parameter it might help you:
Expression.Sql(new SqlString(new object[]{"(this_.data -> 'glossary' ->> 'GlossDiv')::jsonb ? ", Parameter.Placeholder}), "testValue", NHibernateUtil.String);

Related

`?` placeholder for SQL `IN` condition with persistent's `rawSql`

I would be happy to use ? placeholder to populate ids for SQL IN clause. Unfortunately the following does not work
let idList :: [ RequestId ]
idList = []
let sql :: String
sql = "SELECT ?? FROM request WHERE request.id IN ?"
rs <- runDB $ rawSql sql [ toPersistValue idList ]
Such code results in database error similar to:
syntax error at or near "'[283,282,281]'"
Wrapping ? placeholder with brackets (e.g. IN (?)) gives another type of error:
invalid input syntax for integer: "[283,282,281]"
Is there a way to accomplish this?
P.S. Looks like it's a horrible title, have no idea how to improve that
I don't think there is a way to do it with persistent.
postrgresql-simple (assuming that we are talking about Postgres here) which is used by persistent does have special In construct which is correctly translated into In (..) in SQL, but persistent doesn't seem to use it.
One may hope that a workaround is to use PersistDbSpecific constructor which takes ByteString as an argument (so we could manually render and pass something like (123,456,789)) but unfortunately it is converted into SQL via Unknown which is then rendered via Escape which not only escapes the string but also encloses it into quotes which makes our SQL invalid. If persistent were using Plain (which in my view would make much more sence) this approach would work, but unfortunately it is not the case.
The solution is to not use IN, but the more flexible ANY function:
let idList :: [ RequestId ]
idList = []
let sql :: String
sql = "SELECT ?? FROM request WHERE request.id = ANY(?)"
rs <- runDB $ rawSql sql [ PersistArray (map toPersistValue idList) ]
(PersistArray makes sure persistent renders the list using array literals. toPersistValue alone gives a syntax error).
You can read more about the syntax at https://www.postgresql.org/docs/13/functions-comparisons.html (look at the ANY/SOME (array) section).

Limit operator (if variable>value then variable=value)

Is there such a thing as a Limit operator that lets you control the maximum or minium value of a variable.
if variable > value then variable = value
My question is not language specific, but answers in different languages are appreciated (esp. Delhpi).
I know operators differ from language to language, but mostly in syntax.
Would an operator like this be usefull enough?
Some languages have "min" operator that can be used for this: variable = min(variable, limit)
Basically, an operator is nothing else than a function.
Unary operators like ! (not) can be mapped with the function
Boolean not(Boolean)
Binary operators like + (plus) can be mapped with the function
Integer plus(Integer, Integer)
...
So, you can define any missing "operator" on your own as a function. Many languages don't allow to define operators on your own. In Groovy you can overload existing operators:
http://groovy.codehaus.org/Operator+Overloading

Negating a string to be passed to mssql server

I have a text field which acts a filter field. It checks for equals, contains and starts with. My problem is, with out changing any of my code, can I check for the 'does not contain', 'does not start with' and so on by just using the string i'm passing with something like '!' operator or "<>"?
for example:
I want to get all the records that do not have 'a' in them, so can I pass the string as "!a" or "<>a" or something so that I can get the required records? (I know these two don't work cause I tried.)
You have to use the keyword NOT, e.g.
SELECT * FROM Table WHERE Foo NOT LIKE '%bar%'
Please refer http://www.sqlservercentral.com/Forums/Topic1213442-338-1.aspx
Can solve with case in where clause

Is there a way to use the LIKE operator from an entity framework query?

OK, I want to use the LIKE keyword from an Entity Framework query for a rather unorthodox reason - I want to match strings more precisely than when using the equals operator.
Because the equals operator automatically pads the string to be matched with spaces such that col = 'foo ' will actually return a row where col equals 'foo' OR 'foo ', I want to force trailing whitespaces to be taken into account, and the LIKE operator actually does that.
I know that you can coerce Entity Framework into using the LIKE operator using .StartsWith, .EndsWith, and .Contains in a query. However, as might be expected, this causes EF to prefix, suffix, and surround the queried text with wildcard % characters. Is there a way I can actually get Entity Framework to directly use the LIKE operator in SQL to match a string in a query of mine, without adding wildcard characters? Ideally it would look like this:
string usernameToMatch = "admin ";
if (context.Users.Where(usr => usr.Username.Like(usernameToMatch)).Any()) {
// An account with username 'admin ' ACTUALLY exists
}
else {
// An account with username 'admin' may exist, but 'admin ' doesn't
}
I can't find a way to do this directly; right now, the best I can think of is this hack:
context.Users.Where(usr =>
usr.Username.StartsWith(usernameToMatch) &&
usr.Username.EndsWith(usernameToMatch) &&
usr.Username == usernameToMatch
)
Is there a better way? By the way I don't want to use PATINDEX because it looks like a SQL Server-specific thing, not portable between databases.
There isn't a way to get EF to use LIKE in its query, However you could write a stored procedure that finds users using LIKE with an input parameter and use EF to hit your stored procedure.
Your particular situation however seems to be more of a data integrity issue though. You shouldn't be allowing users to register usernames that start or end with a space (username.Trim()) for pretty much this reason. Once you do that then this particular issue goes away entirely.
Also, allowing 'rough' matches on authentication details is beyond insecure. Don't do it.
Well there doesn't seem to be a way to get EF to use the LIKE operator without padding it at the beginning or end with wildcard characters, as I mentioned in my question, so I ended up using this combination which, while a bit ugly, has the same effect as a LIKE without any wildcards:
context.Users.Where(usr =>
usr.Username.StartsWith(usernameToMatch) &&
usr.Username.EndsWith(usernameToMatch) &&
usr.Username == usernameToMatch
)
So, if the value is LIKE '[usernameToMatch]%' and it's LIKE '%[usernameToMatch]' and it = '[usernameToMatch]' then it matches exactly.

SQLiteQueryBuilder.buildQuery not using selectArgs?

Alright, I'm trying to query a sqlite database. I was trying to be good and use the query method of SQLiteDatabase and pass in the values in the selectArgs parameter to ensure everything got properly escaped, but it wouldn't work. I never got any rows returned (no errors, either).
I started getting curious about the SQL that this generated so I did some more poking around and found SQLiteQueryBuilder (and apparently Stack Overflow doesn't handle links with parentheses in them well, so I can't link to the anchor for the buildQuery method), which I assume uses the same logic to generate the SQL statement. I did this:
SQLiteQueryBuilder builder = new SQLiteQueryBuilder();
builder.setTables(BarcodeDb.Barcodes.TABLE_NAME);
String sql = builder.buildQuery(new String[] { BarcodeDb.Barcodes.ID, BarcodeDb.Barcodes.TIMESTAMP, BarcodeDb.Barcodes.TYPE, BarcodeDb.Barcodes.VALUE },
"? = '?' AND ? = '?'",
new String[] { BarcodeDb.Barcodes.VALUE, barcode.getValue(), BarcodeDb.Barcodes.TYPE, barcode.getType()},
null, null, null, null);
Log.d(tag, "Query is: " + sql);
The SQL that gets logged at this point is:
SELECT _id, timestamp, type, value FROM barcodes WHERE (? = '?' AND ? = '?')
However, here's what the documentation for SQLiteQueryBuilder.buildQuery says about the selectAgs parameter:
You may include ?s in selection, which
will be replaced by the values from
selectionArgs, in order that they
appear in the selection.
...but it isn't working. Any ideas?
The doc for SQLiteQueryBuilder.buildQuery also says, "The values will be bound as Strings." This tells me that it is doing the straight-forward thing, which is writing the SQL leaving the ? parameter markers in place, which is what you are seeing, and binding the selectArgs as input parameters.
The ? are replaced by sqlite when it runs the query, not in the SQL string. The first string in the array will go where you see the first ?, and so on, when the query actually executes. I would expect the logged SQL to still have the ? markers.
Probably, your query fails because you are quoting the ?. For example, don't use WHERE ID = '?', just use WHERE ID = ?, and make sure the selectArgs is a string that satisfies the query.
Two things:
The ? substitution will not be done at this point, but only when the query is executed by the SQLiteDatabase.
From what I've seen, ? substitution only works for the right side of comparison clauses. For example, some people have tried to use ? for the table name, which blows up. I haven't seen anyone try using ? for the left side of the comparison clause, so it might work -- I'm just warning you that it might not.