Re: [Firebird-devel] Firebird 5 and Update...Returning

2021-11-26 Thread Dimitry Sibiryakov

Tony Whyman wrote 26.11.2021 18:01:
Note that only if FGoToFirstRecordOnExecute is true will the returned values be 
available immediately.


  Which (accidentally) is default and has no sense to be changed ever.

--
  WBR, SD.


Firebird-Devel mailing list, web interface at 
https://lists.sourceforge.net/lists/listinfo/firebird-devel


Re: [Firebird-devel] Firebird 5 and Update...Returning

2021-11-26 Thread Tony Whyman
That code is very legacy and dates from a time when Update..Returning 
did not exist.


Actually, it works the same as the modern version. My point was about 
what the user expects. If you execute an Update...Returning with the 
code you pasted in below, with Firebird 4.0.0 it drops through the 
SQLExecProcedure and the user can access the returned values immediately 
afterwards.


In Firebird 5, the code executes the SQLSelect case. Note that only if 
FGoToFirstRecordOnExecute is true will the returned values be available 
immediately. Otherwise, the user has to call "Next" explicitly. That is 
why the change to Update...Returning can break user code.


In order to try and maintain the TIBSQL semantics for Firebird 5, I need 
to be able to distinguish between a true select query, an 
Update...Returning that returns a singleton row and one that returns a 
cursor. I may be able to find an answer by experimenting with the new 
behaviour, but that will not stop me moaning that the extension of 
Update..Returning has been implemented without keeping faith with 
existing code.


On 26/11/2021 16:47, Dimitry Sibiryakov wrote:

Tony Whyman wrote 26.11.2021 17:13:
Legacy code can often appear "insane" with the benefit of hindsight. 
The problem is that it exists and it is your starting point. You 
don't break it without good reason.


  Ok, here is legacy code from TIBSQL.ExecQuery:

  case FSQLType of
    SQLSelect:
    begin
  Call(FGDSLibrary.isc_dsql_execute2(StatusVector,
    TRHandle,
    @FHandle,
    Database.SQLDialect,
    FSQLParams.AsXSQLDA,
    nil), True);
  Call(
    FGDSLibrary.isc_dsql_set_cursor_name(StatusVector, @FHandle, 
PChar(FCursor), 0),

    True);
  FOpen := True;
  FBOF := True;
  FEOF := False;
  FRecordCount := 0;
  if FGoToFirstRecordOnExecute then
    Next;
    end;
    SQLExecProcedure:
    begin
  fetch_res := Call(FGDSLibrary.isc_dsql_execute2(StatusVector,
    TRHandle,
    @FHandle,
    Database.SQLDialect,
    FSQLParams.AsXSQLDA,
    FSQLRecord.AsXSQLDA), False);
. and so on...

  As you can see it IS sane and won't be broken so if _current_ IBX 
code differs from it - the one who "improved" it must be blamed. 
Firebird team cannot help in this case.





Firebird-Devel mailing list, web interface at 
https://lists.sourceforge.net/lists/listinfo/firebird-devel


Re: [Firebird-devel] Firebird 5 and Update...Returning

2021-11-26 Thread Mark Rotteveel

On 26-11-2021 17:13, Tony Whyman wrote:

On 26/11/2021 15:43, Dimitry Sibiryakov wrote:

Tony Whyman wrote 26.11.2021 16:32:
What you appear to be saying is that you have changed/expanded the 
semantic of Update...Returning, changed the SQL Statement type 
returned and then not expected the change to break any existing code...


  Correction: any sane code.

There is an old joke that starts with one person asking another the way 
to Edinburgh. The answer given is "I wouldn't start from here if I were 
you".


That answer may be true, but very unhelpful. Legacy code can often 
appear "insane" with the benefit of hindsight. The problem is that it 
exists and it is your starting point. You don't break it without good 
reason.


There is a good reason: supporting multi-row RETURNING instead of the 
limitation in FB 4.0 and earlier of only supporting singleton updates. 
And this is done in a way that query tools and drivers inspecting the 
statement type will still be able to process it appropriately.


The reasoning is similar as why isc_info_sql_stmt_exec_procedure was 
used when RETURNING was introduced in Firebird 2.0[1]:

"""
If the RETURNING clause is present, then the statement is described as 
isc_info_sql_stmt_exec_procedure by the API (instead of 
isc_info_sql_stmt_insert), so the existing connectivity drivers should 
support this feature automagically.

"""

Maybe Firebird shouldn't have implemented RETURNING at all, but instead 
implemented the SQL standard way of doing this using the data change 
delta table:


`select * from final table (update sometable set x = 'a')`

(or `select * from new table (update sometable set x = 'a')` or `select 
* from old table (update sometable set x = 'a')`)


However, the semantics of supporting data change delta table is a bit 
more complex (from a quick read of the standard).


Mark

 [1]: 
https://firebirdsql.org/file/documentation/release_notes/html/rlsnotes207.html#dml-dsql-returning

--
Mark Rotteveel


Firebird-Devel mailing list, web interface at 
https://lists.sourceforge.net/lists/listinfo/firebird-devel


Re: [Firebird-devel] Firebird 5 and Update...Returning

2021-11-26 Thread Dimitry Sibiryakov

Tony Whyman wrote 26.11.2021 17:13:
Legacy code can often appear "insane" with the benefit of hindsight. The problem 
is that it exists and it is your starting point. You don't break it without good 
reason.


  Ok, here is legacy code from TIBSQL.ExecQuery:

  case FSQLType of
SQLSelect:
begin
  Call(FGDSLibrary.isc_dsql_execute2(StatusVector,
TRHandle,
@FHandle,
Database.SQLDialect,
FSQLParams.AsXSQLDA,
nil), True);
  Call(
FGDSLibrary.isc_dsql_set_cursor_name(StatusVector, @FHandle, 
PChar(FCursor), 0),

True);
  FOpen := True;
  FBOF := True;
  FEOF := False;
  FRecordCount := 0;
  if FGoToFirstRecordOnExecute then
Next;
end;
SQLExecProcedure:
begin
  fetch_res := Call(FGDSLibrary.isc_dsql_execute2(StatusVector,
TRHandle,
@FHandle,
Database.SQLDialect,
FSQLParams.AsXSQLDA,
FSQLRecord.AsXSQLDA), False);
. and so on...

  As you can see it IS sane and won't be broken so if _current_ IBX code 
differs from it - the one who "improved" it must be blamed. Firebird team cannot 
help in this case.


--
  WBR, SD.


Firebird-Devel mailing list, web interface at 
https://lists.sourceforge.net/lists/listinfo/firebird-devel


Re: [Firebird-devel] Firebird 5 and Update...Returning

2021-11-26 Thread Dmitry Yemanov

26.11.2021 17:47, Tony Whyman wrote:


3. IBX tries to be general purpose and so prepares a statement, then 
checks the statement type, and then calls the appropriate IStatement 
method. 


Then it shouldn't be broken. It gets isc_info_sql_stmt_select, calls 
openCursor() and everything works as intended.


Changing the statement type semantics broke the logic used to 
determine which method to call.


I still don't see how it was broken, sorry. See above.


Dmitry


Firebird-Devel mailing list, web interface at 
https://lists.sourceforge.net/lists/listinfo/firebird-devel


Re: [Firebird-devel] Firebird 5 and Update...Returning

2021-11-26 Thread Tony Whyman

On 26/11/2021 15:43, Dimitry Sibiryakov wrote:

Tony Whyman wrote 26.11.2021 16:32:
What you appear to be saying is that you have changed/expanded the 
semantic of Update...Returning, changed the SQL Statement type 
returned and then not expected the change to break any existing code...


  Correction: any sane code.

There is an old joke that starts with one person asking another the way 
to Edinburgh. The answer given is "I wouldn't start from here if I were 
you".


That answer may be true, but very unhelpful. Legacy code can often 
appear "insane" with the benefit of hindsight. The problem is that it 
exists and it is your starting point. You don't break it without good 
reason.




Firebird-Devel mailing list, web interface at 
https://lists.sourceforge.net/lists/listinfo/firebird-devel


Re: [Firebird-devel] Firebird 5 and Update...Returning

2021-11-26 Thread Dimitry Sibiryakov

Tony Whyman wrote 26.11.2021 16:32:
What you appear to be saying is that you have changed/expanded the semantic of 
Update...Returning, changed the SQL Statement type returned and then not 
expected the change to break any existing code...


  Correction: any sane code.

If a singleton row is expected then there is no need to do either of the above. Right now, I am not sure how this behaviour can be maintained (and not get inundated by users complaining that their code is broken) without being able to tell the difference between an Update...Returning that returns a singleton row from one that returns a cursor. 


  This behavior can be maintained exactly as it has been done: if statement 
type is isc_info_sql_stmt_exec_procedure - single row is expected, if statement 
type is isc_info_sql_stmt_select - multiple rows are expected. And IIRC TIBSQL's 
code was written exactly like this.



  No, openCursor() must be called here, not execute().
Which is, of course, new behaviour. 


  No, it is the old behavior. If statement type is described as select - open 
cursor. If it is procedure call - get singleton.


  And once again: execute() should work as well as long as UPDATE is changing 
exactly one record.



--
  WBR, SD.


Firebird-Devel mailing list, web interface at 
https://lists.sourceforge.net/lists/listinfo/firebird-devel


Re: [Firebird-devel] Firebird 5 and Update...Returning

2021-11-26 Thread Mark Rotteveel

On 26-11-2021 16:32, Tony Whyman wrote:
What you appear to be saying is that you have changed/expanded the 
semantic of Update...Returning, changed the SQL Statement type returned 
and then not expected the change to break any existing code...


The change was done in a way that code looking at the statement type to 
know how to execute it would not break, and without adding a new 
statement type, so libraries not updated for this would still be able to 
handle it correctly.


See also the discussion with subject 
"isc_info_sql_stmt_type/isc_info_sql_stmt_flags" back on the 19th and 
20th of August 2021.


Mark
--
Mark Rotteveel


Firebird-Devel mailing list, web interface at 
https://lists.sourceforge.net/lists/listinfo/firebird-devel


Re: [Firebird-devel] Firebird 5 and Update...Returning

2021-11-26 Thread Tony Whyman
What you appear to be saying is that you have changed/expanded the 
semantic of Update...Returning, changed the SQL Statement type returned 
and then not expected the change to break any existing code...



On 26/11/2021 15:01, Dimitry Sibiryakov wrote:

Tony Whyman wrote 26.11.2021 15:28:
3. Prior to calling IStatement.Execute, the statement type is 
checked. The current (IBX) code raises an exception if the sql 
statement type is isc_info_sql_stmt_select in order to stop the wrong 
IStatement method being called.


  So it is actually the test suite that makes (now wrong) assumption 
that UPDATE...RETURNING has to be described as 
isc_info_sql_stmt_exec_procedure is wrong.


But it used to be the correct assumption.



3. IBX tries to be general purpose and so prepares a statement, then 
checks the statement type, and then calls the appropriate IStatement 
method. Changing the statement type semantics broke the logic used to 
determine which method to call. 


  That's why the change. IBX should check the statement type (which 
now is isc_info_sql_stmt_select) and call appropriate method i.e. 
openCursor(). What's wrong?
The problem is in TIBSQL. This is a class that goes all the way back to 
Borland days. It has a common method "ExecQuery" that is called 
regardless of the statement type. If it is used to open a cursor, then 
the user either has to set the GoToFirstRecordOnExecute property to 
ensure that the cursor is automatically positioned on the first row, or 
explicitly call "Next". If a singleton row is expected then there is no 
need to do either of the above. Right now, I am not sure how this 
behaviour can be maintained (and not get inundated by users complaining 
that their code is broken) without being able to tell the difference 
between an Update...Returning that returns a singleton row from one that 
returns a cursor.


4. With reference to item 1 above, if "Update..Returning" returns a 
statement type of isc_info_sql_stmt_select then you _do_ have to also 
parse the statement in IBX so that you know its an UPDATE and 
IStatement.execute has to be called instead of IStatement.openCursor. 


  No, openCursor() must be called here, not execute().

Which is, of course, new behaviour.


Firebird-Devel mailing list, web interface at 
https://lists.sourceforge.net/lists/listinfo/firebird-devel


Re: [Firebird-devel] Firebird 5 and Update...Returning

2021-11-26 Thread Dimitry Sibiryakov

Dimitry Sibiryakov wrote 26.11.2021 16:01:
4. With reference to item 1 above, if "Update..Returning" returns a statement 
type of isc_info_sql_stmt_select then you _do_ have to also parse the 
statement in IBX so that you know its an UPDATE and IStatement.execute has to 
be called instead of IStatement.openCursor. 


   No, openCursor() must be called here, not execute().


  Actually, execute() also should work as long as the query updates only one 
record.


--
  WBR, SD.


Firebird-Devel mailing list, web interface at 
https://lists.sourceforge.net/lists/listinfo/firebird-devel


Re: [Firebird-devel] Firebird 5 and Update...Returning

2021-11-26 Thread Dimitry Sibiryakov

Tony Whyman wrote 26.11.2021 15:28:
3. Prior to calling IStatement.Execute, the statement type is checked. The 
current (IBX) code raises an exception if the sql statement type is 
isc_info_sql_stmt_select in order to stop the wrong IStatement method being called.


  So it is actually the test suite that makes (now wrong) assumption that 
UPDATE...RETURNING has to be described as isc_info_sql_stmt_exec_procedure is wrong.


3. IBX tries to be general purpose and so prepares a statement, then checks the statement type, and then calls the appropriate IStatement method. Changing the statement type semantics broke the logic used to determine which method to call. 


  That's why the change. IBX should check the statement type (which now is 
isc_info_sql_stmt_select) and call appropriate method i.e. openCursor(). What's 
wrong?


4. With reference to item 1 above, if "Update..Returning" returns a statement type of isc_info_sql_stmt_select then you _do_ have to also parse the statement in IBX so that you know its an UPDATE and IStatement.execute has to be called instead of IStatement.openCursor. 


  No, openCursor() must be called here, not execute().

--
  WBR, SD.


Firebird-Devel mailing list, web interface at 
https://lists.sourceforge.net/lists/listinfo/firebird-devel


Re: [Firebird-devel] Firebird 5 and Update...Returning

2021-11-26 Thread Alex Peshkoff via Firebird-devel

On 11/26/21 5:47 PM, Tony Whyman wrote:

On 26/11/2021 14:32, Dmitry Yemanov wrote:

26.11.2021 17:28, Tony Whyman wrote:

1. IAttachment.prepare is used to parse 'Update Employee Set 
Hire_Date = ? Where EMP_NO = ? Returning LAST_NAME'


2. IStatement.getType is then used to determine the statement type.


OK so far.

3. Prior to calling IStatement.Execute, the statement type is 
checked. The current (IBX) code raises an exception if the sql 
statement type is isc_info_sql_stmt_select in order to stop the 
wrong IStatement method being called.


Why? How is it different from SELECT returning 
isc_info_sql_stmt_select? They should work the same way. Is the SQL 
text also parsed to detect UPDATE and that conflicts with the 
returned statement type?



Dmitry


1. This is not a backwards compatible change. If "Update...Returning" 
had always been given a statement type of isc_info_sql_stmt_select 
then the IBX code would have been written to support this. As it 
happens, it was not and so changing the statement type immediately 
introduces a backwards compatibility issue. Do you have a good reason 
to make this change?


Support multiple rows returned from this statement.
BTW - how do you determine that statement is "Update...Returning" ? Own 
parser?




2. IStatement has different methods "execute" and "openCursor". You 
need to know in advance which one to call. The former is called when 
you expect a singleton row (or no output) and the latter when you 
expect a cursor.


Exactly. This is decided best of all based on 
Statement::getFlags(status), is flag Statement::FLAG_HAS_CURSOR set or not.




3. IBX tries to be general purpose and so prepares a statement, then 
checks the statement type, and then calls the appropriate IStatement 
method. Changing the statement type semantics broke the logic used to 
determine which method to call.


Why?



4. With reference to item 1 above, if "Update..Returning" returns a 
statement type of isc_info_sql_stmt_select then you _do_ have to also 
parse the statement in IBX so that you know its an UPDATE and 
IStatement.execute has to be called instead of IStatement.openCursor.




After currently discussed change openCursor() should be called for 
"Update..Returning", not execute.





Firebird-Devel mailing list, web interface at 
https://lists.sourceforge.net/lists/listinfo/firebird-devel


Re: [Firebird-devel] Firebird 5 and Update...Returning

2021-11-26 Thread Tony Whyman

On 26/11/2021 14:32, Dmitry Yemanov wrote:

26.11.2021 17:28, Tony Whyman wrote:

1. IAttachment.prepare is used to parse 'Update Employee Set 
Hire_Date = ? Where EMP_NO = ? Returning LAST_NAME'


2. IStatement.getType is then used to determine the statement type.


OK so far.

3. Prior to calling IStatement.Execute, the statement type is 
checked. The current (IBX) code raises an exception if the sql 
statement type is isc_info_sql_stmt_select in order to stop the wrong 
IStatement method being called.


Why? How is it different from SELECT returning 
isc_info_sql_stmt_select? They should work the same way. Is the SQL 
text also parsed to detect UPDATE and that conflicts with the returned 
statement type?



Dmitry


1. This is not a backwards compatible change. If "Update...Returning" 
had always been given a statement type of isc_info_sql_stmt_select then 
the IBX code would have been written to support this. As it happens, it 
was not and so changing the statement type immediately introduces a 
backwards compatibility issue. Do you have a good reason to make this 
change?


2. IStatement has different methods "execute" and "openCursor". You need 
to know in advance which one to call. The former is called when you 
expect a singleton row (or no output) and the latter when you expect a 
cursor.


3. IBX tries to be general purpose and so prepares a statement, then 
checks the statement type, and then calls the appropriate IStatement 
method. Changing the statement type semantics broke the logic used to 
determine which method to call.


4. With reference to item 1 above, if "Update..Returning" returns a 
statement type of isc_info_sql_stmt_select then you _do_ have to also 
parse the statement in IBX so that you know its an UPDATE and 
IStatement.execute has to be called instead of IStatement.openCursor.




Firebird-Devel mailing list, web interface at 
https://lists.sourceforge.net/lists/listinfo/firebird-devel


Re: [Firebird-devel] Firebird 5 and Update...Returning

2021-11-26 Thread Dmitry Yemanov

26.11.2021 17:28, Tony Whyman wrote:

1. IAttachment.prepare is used to parse 'Update Employee Set Hire_Date = 
? Where EMP_NO = ? Returning LAST_NAME'


2. IStatement.getType is then used to determine the statement type.


OK so far.

3. Prior to calling IStatement.Execute, the statement type is checked. 
The current (IBX) code raises an exception if the sql statement type is 
isc_info_sql_stmt_select in order to stop the wrong IStatement method 
being called.


Why? How is it different from SELECT returning isc_info_sql_stmt_select? 
They should work the same way. Is the SQL text also parsed to detect 
UPDATE and that conflicts with the returned statement type?



Dmitry


Firebird-Devel mailing list, web interface at 
https://lists.sourceforge.net/lists/listinfo/firebird-devel


Re: [Firebird-devel] Firebird 5 and Update...Returning

2021-11-26 Thread Tony Whyman

On 26/11/2021 14:16, Dimitry Sibiryakov wrote:

Tony Whyman wrote 26.11.2021 15:10:
This caused an error message to be generated because only a singleton 
row was expected and not a cursor.


Well, all I can say is that "existing connectivity drivers do not 
support this feature automagically". Is it really then intended 
behaviour for Update...Returning to now return an SQL Type of 
isc_info_sql_stmt_select?


  Yes. What exactly call produces the error message and what exactly 
is the error?


1. IAttachment.prepare is used to parse 'Update Employee Set Hire_Date = 
? Where EMP_NO = ? Returning LAST_NAME'


2. IStatement.getType is then used to determine the statement type.

3. Prior to calling IStatement.Execute, the statement type is checked. 
The current (IBX) code raises an exception if the sql statement type is  
isc_info_sql_stmt_select in order to stop the wrong IStatement method 
being called.


Note that the exception is called by IBX and not Firebird. However, the 
exception is consequential on Firebird returning the statement type 
isc_info_sql_stmt_select when all previous versions of Firebird had 
returned isc_info_sql_stmt_exec_procedure for an Update...Returning 
statement.




Firebird-Devel mailing list, web interface at 
https://lists.sourceforge.net/lists/listinfo/firebird-devel


Re: [Firebird-devel] Firebird 5 and Update...Returning

2021-11-26 Thread Dimitry Sibiryakov

Tony Whyman wrote 26.11.2021 15:10:
This caused an error message to be generated because only a singleton row was 
expected and not a cursor.


Well, all I can say is that "existing connectivity drivers do not support this 
feature automagically". Is it really then intended behaviour for 
Update...Returning to now return an SQL Type of isc_info_sql_stmt_select?


  Yes. What exactly call produces the error message and what exactly is the 
error?

--
  WBR, SD.


Firebird-Devel mailing list, web interface at 
https://lists.sourceforge.net/lists/listinfo/firebird-devel


[Firebird-devel] Firebird 5 and Update...Returning

2021-11-26 Thread Tony Whyman
When testing out Dimtry's recent fix for scrollable cursors (adding 
support for the remote protocol), I ran the full IBX test suite on the 
current "master" branch. This flagged up a backwards compatibility issue 
with "Update...Returning".


When the statement:

'Update Employee Set Hire_Date = ? Where EMP_NO = ? Returning LAST_NAME'

was prepared, the SQL type was returned as isc_info_sql_stmt_select. The 
previous behaviour was to return isc_info_sql_stmt_exec_procedure. This 
caused an error message to be generated because only a singleton row was 
expected and not a cursor.


The file doc/sql.extensions/README.returning has been updated and a 
quick diff with 4.0.0 returned, amongst other changes:



45,46c45,47
<    isc_info_sql_stmt_exec_procedure by the API (instead of 
isc_info_sql_stmt_insert),
<    so the existing connectivity drivers should support this 
feature automagically.

---
>    isc_info_sql_stmt_exec_procedure by the API (for INSERT INTO 
... VALUES and statements
>    with WHERE CURRENT OF) and isc_info_sql_stmt_select for the 
others statements, so the
>    existing connectivity drivers should support this feature 
automagically.


Well, all I can say is that "existing connectivity drivers do not 
support this feature automagically". Is it really then intended 
behaviour for Update...Returning to now return an SQL Type of 
isc_info_sql_stmt_select?


Tony Whyman

MWA



Firebird-Devel mailing list, web interface at 
https://lists.sourceforge.net/lists/listinfo/firebird-devel