Change parameters to fixed values in offset\fetch clause - nhibernate

I am using NHibernate with Progress OpenEdge 11.3 Update 2 ODBC Driver. The driver (or OpenEdge) does not allow parameters in offset\fetch clauses. The offset\fetch clause must contain fixed values. According to the documentation and this article:
http://knowledgebase.progress.com/articles/Article/2916
Not allowed:
select * from PUB.customer offset ? rows fetch next ? rows
Execption:
ERROR [HY000] [DataDirect][ODBC Progress OpenEdge Wire Protocol driver][OPENEDGE]Syntax error in SQL statement at or about "? rows fetch next ? rows only " (10713)
Allowed:
select * from PUB.customer offset 10 rows fetch next 10 rows
How can I modify NHibernate's behaviour to use fixed values instead of parameters, when using Linq?
var customers = session.Query().Skip(10).Take(10).ToList();
Maybe someone can point me to the right direction. I have already downloaded the NHibernate sources and debugged them, but I could not find the right place to replace the parameters.
Thanks!

I found a solution:
I set UseVariableLimits to false within my custom Nhibernate ODBC dialect. Furthermore, I installed the NHibernate 4.0.0.-Alpha2 nuget package.
This fixed the problem. Hope that NHibernate 4.0.0 will be stable and released soon.

Related

How to use PLAN with UPDATE OR INSERT INTO

I am using Firebird 2.5 and came across a problem that I can not resolve by myself.
There is a statement using UPDATE OR INSERT INTO. I would like to make it use a specific execution plan. But - no matter where I place the PLAN - I get following error message (line number varies with PLAN's position):
Invalid token.
Dynamic SQL Error.
SQL error code = -104.
Token unknown - line 2, column 5.
plan.
I did not find anything about the usage of PLAN with UPDATE OR INSERT INTO in the corresponding documentation.
Aspects of my question: Is it even possible to use them together? Does this work or is it planned to work in a later version of Firebird? Is there an obvious reason it does not work, that I did not see? Which alternatives exist to circumvent this?
It is not possible to do this in Firebird 2.5 (and also not possible in 3.0). Looking at the parser definition, the PLAN clause is only supported on:
select query specification
searched delete
searched update
For a merge statement it should be possible to specify a plan for the source (if it is a select query), but not for the merge itself. The plan clause is not defined for update or insert (nor is it for insert, for example).
As far as I am aware there is nothing planned to add this to Firebird 4. You should consider adding an improvement ticket in the tracker, but I don't know if this is even possible at all.

How to retrieve the auto incremented ID using slick / plainSQL?

Isn't there a slick/plainSQL native solution to retrieve the auto incremented id of the current INSERT?
userId is an auto incremental field in my mySQL table.
sql"""
INSERT INTO `table`(`email`)
OUTPUT INSERTED.userId
VALUES ("theEmailAdress#test.de")
""".as[Int].firstOption
Help would be greatly appreciated.
Cheers
Oliver
Depends on the database.
For MS SQL it's SCOPE_IDENTITY(), for mySQL it's LAST_INSERT_ID().
Try searching for equivalent for your DB if it's none of the above.
Added by cvogt:
There is currently no slick-built-in feature for plain SQL for this and no way to access the underlying jdbc statement when using Slick's sql"..." interpolation or StaticQuery, which would allow you to access getGeneratedKeys. You could probably patch the SQL interpolator and StatementInvoker to allow this. They are just 150 LOC. Maybe worth giving a shot and submitting a PR.
You could however use one of the Slick session method like withPreparedInsertStatement, which wrap jdbc connection methods to work with a jdbc statement. I created a PR to add documentation about this: https://github.com/slick/slick/pull/691
Thank you cvogt for helping out in this discussion.
I think it would be helpful to submit a PR, inasmuch as it is a very common and useful functionality which should not be missing in slick's plainSQL queries.
Finally, i found a work-around to replace the missing native function as following.
Within the same session I settle two queries. The first one is the INSERT statement, the second statement is SELECT LAST_INSERT_ID() which returns the newest automatically generated value that was set for the AUTO_INCREMENT column by the recently executed INSERT(1). More details here: MySQL Reference - LAST_INSERT_ID()
Database.forDataSource(dataSource).withDynSession {
sqlu"""INSERT INTO `users`(`email`) VALUES ("theEmailAdress#test.de")
""".firstOption match {
case Some(num) if num == 1 => sql"SELECT LAST_INSERT_ID()".as[Long].firstOption()
case None => None
}
}
This works for me right now. If there are any improvements, do not hesitate to post your solution.

How to limit select result rows in Progress 9.1D09?

I'm trying to extract data from a Progress 9.1D09 database. I understand that this isn't the latest version of Progress but upgrading isn't an option. The database is used by a dying program and I am moving the data to its successor.
One table has 162000 rows. I want to work with a small number of rows.
In SQL Server I would change my query to "select top 100 * from ...". In MySQL I would do "select * from ... limit 0,100".
Neither of these syntaxes work and googling for the right syntax has failed me so far.
How can I limit the number of rows in the source data using SQL?
Rule #1 -- Progress is not SQL. Progress does support a SQL-92 interface and it also has SQL-89 syntax embedded -- but SQL is not the native tongue for a Progress DB.
If you are using the embedded SQL-89 there is no support for TOP. The embedded SQL is accessed via the 4GL engine. If you are not using ODBC or JDBC you are probably trying to use embedded SQL-89. If syntax like:
FOR EACH customer NO-LOCK:
DISPLAY customer.
END.
works then you are using the 4GL and thus the embedded SQL-89.
A 4GL solution might look like this:
Getting first 100 records from the table in Progress OpenEdge database (e.g. SELECT TOP 100..)
If you are using SQL-92 via ODBC drivers -- TOP support was added sometime in 10.1B
http://knowledgebase.progress.com/articles/Article/P13258
So you're out of luck with v9.
You can try rownumber something like
SELECT FirstName, LastName, ROW_NUMBER()
OVER (ORDER BY PostalCode) AS 'RowNumber'
WHERE RowNumber BETWEEN(4,100)

Hsqldb rownum in UPDATE statement

Hallo, I've a problem with this query :
update EXAMPLETABLE set FLAG = 1 where FLAG = 0 and rownum < 10;
This query is working in Oracle (it updates exactly 9 rows), but not in my testcase with hsqldb (the statement updates ALL the rows in EXAMPLETABLE).
I'm using also
SET DATABASE SQL SYNTAX ORA TRUE;
in hsqlDb generation script.
I'm using hsqlDb in-memory only.
Is this feature not implemented in hsqlDb?
Thanks,
Roberto
This feature is not implemented in HSQLDB. It may be supported in ORACLE mode in the near future. (update: now supported in 2.2.6 and later versions).
There is a problem in principle about this type of statement. As the rows could be returned in any order, an update is performed on an almost arbitrary subset of rows with the given FLAG setting.

IBDAC / UniDAC + interbase 6 or 7 + a table field named "returning"

I am porting REALLY old code to use the UniDAC components. I have hit a wall with a specific UPDATE sql that changes a field named "returning." Simply wrapping the field in quotes does not resolve the issue, because the SQL dialect in the database is 1, which does not support double quote field delimiters. Is there any way around this without changing the field? I am on delphi 7, and am moving away from the interbase db components.
Edit: SQL is as follows:
update logger set
returning = :RETURNING
where locator = :LOCATOR
returns the following error when trying to prepare:
---------------------------
Ww
---------------------------
Dynamic SQL Error
SQL error code = -104
Token unknown - line 3, char -1
where.
---------------------------
OK
---------------------------
This occurs even when I set the client SQL dialect to 1 in code:
query1.Connection.SpecificOptions.Values['SQLDialect'] := '1';
I had to talk to the developer. It has been addressed to a certain point, but I need to remove all parameters in the query before executing it. Very odd, but its a workaround :/
Is it possible for you to create a view leaving everything the same except for this field and use that view in your application?
Is it possible to run this application with the client dll of a Firebird < 2.1 (1.5 for example) and a server with the same version?
I think this is due to the new syntax where returning is a reserved word!