Issue with RefreshCurrentRow with no primary key.

Code patches written by our users to solve certain "problems" that were not solved, yet.

Moderators: gto, cipto_kh, EgonHugeist, mdaems

Post Reply
MJFShark
Expert Boarder
Expert Boarder
Posts: 211
Joined: 04.06.2020, 13:59

Issue with RefreshCurrentRow with no primary key.

Post by MJFShark »

NOTE: The issues pointed out below all correspond to tables that don't have a primary key. So this is a bit of a special case, but it would be nice to fix it. See my note below on the RefreshResultSet statement caching.

I noticed when calling RefreshCurrentRow on a query with no primary key and some null values that I got an "number of bind variables doesn't match" type error from Oracle. It seemed that it was binding parameters in the where clause that had been changed to " is null" (and so were no longer meant to be bound.) I may have fixed it with the following change.

It appears that the following line:

Code: Select all

    RowAccessor.FillStatement(Stmt, FWhereColumns, Metadata);
Should be:

Code: Select all

    RowAccessor.FillStatement(Stmt, FCurrentWhereColumns, Metadata);
In the TZGenerateSQLCachedResolver.RefreshCurrentRow method.

-- Update.
The above does fix things initially, however currently this method caches the RefreshResultSet statement and this statement needs to change if there is no primary key and there are any nulls in the current record. Basically if there's no primary key than I think the refresh statement has to be initialized every time.

-Mark
MJFShark
Expert Boarder
Expert Boarder
Posts: 211
Joined: 04.06.2020, 13:59

Re: Issue with RefreshCurrentRow with no primary key.

Post by MJFShark »

To take care of the caching problem I ended up adding "or WhereAll" to the test for InitStmt.

Code: Select all

  if (RefreshResultSet = nil) or (RefreshResultSet.GetStatement = nil) or RefreshResultSet.GetStatement.IsClosed or WhereAll
  then InitStmt(Stmt)
  else RefreshResultSet.GetStatement.QueryInterface(IZPreparedStatement, Stmt);
-Mark
User avatar
aehimself
Zeos Dev Team
Zeos Dev Team
Posts: 766
Joined: 18.11.2018, 17:37
Location: Hungary

Re: Issue with RefreshCurrentRow with no primary key.

Post by aehimself »

Completely offtopic. We have a method called "RefreshCurrentRow"? :O

I have a tool which checks and highlights changes in a record as time elapses. I called Dataset.Refresh but (especially at large resultsets) this can be time consuming.

Seems you used it already, does it worth for me to look into it? Is it a significant improvement?
Delphi 12.1, Zeos 8 from latest GIT snapshot
Using:
- MySQL server 8.0.18; libmariadb.dll 3.3.8
- Oracle server 11.2.0, 12.1.0, 19.0.0; oci.dll 21.13
- MSSQL 2012, 2019; sybdb.dll FreeTDS_2435
- SQLite 3.45.2
MJFShark
Expert Boarder
Expert Boarder
Posts: 211
Joined: 04.06.2020, 13:59

Re: Issue with RefreshCurrentRow with no primary key.

Post by MJFShark »

In my case I use RefreshCurrentRow after a post to reread the values in case they changed (triggers and such.) In my testing it with Oracle I ran into a lot of errors that seem to be related to the refresh statement being cached. The only way that I was able to fix it completely (so far) was to remove the caching completely and initialize the stmt each time RefreshCurrentRow is called, which seems sub-optimal.

-Mark
marsupilami
Platinum Boarder
Platinum Boarder
Posts: 1918
Joined: 17.01.2011, 14:17

Re: Issue with RefreshCurrentRow with no primary key.

Post by marsupilami »

aehimself wrote: 03.06.2021, 20:27 Completely offtopic. We have a method called "RefreshCurrentRow"? :O
We do. We have this method like forever. But the generic resolver never implemented it. The only way to use it was TZUpdateSQL. With Zeos 8 this changed.
aehimself wrote: 03.06.2021, 20:27 Seems you used it already, does it worth for me to look into it? Is it a significant improvement?
It really depends on your use case. It will refresh the current row and no other rows. As far as I know, Egonhugeist implemented it for all drivers.
MJFShark
Expert Boarder
Expert Boarder
Posts: 211
Joined: 04.06.2020, 13:59

Re: Issue with RefreshCurrentRow with no primary key.

Post by MJFShark »

Here's what I ended up with. This just adds two checks for "WhereAll" since if that's true the refresh statement could change each time if there are nulls involved. This retains the refresh statement caching if there's a primary key.

Body of TZGenerateSQLCachedResolver.RefreshCurrentRow

Code: Select all

  if (RefreshResultSet = nil) or (RefreshResultSet.GetStatement = nil) or RefreshResultSet.GetStatement.IsClosed or WhereAll
  then InitStmt(Stmt)
  else RefreshResultSet.GetStatement.QueryInterface(IZPreparedStatement, Stmt);
  if Stmt = nil then
    raise EZSQLException.Create(SUpdateSQLNoResult)
  else begin
    if WhereAll then
      RowAccessor.FillStatement(Stmt, FCurrentWhereColumns, Metadata)
    else
      RowAccessor.FillStatement(Stmt, FWhereColumns, Metadata);
    RefreshResultSet := Stmt.ExecuteQueryPrepared;
    if (RefreshResultSet = nil) or not RefreshResultSet.Next then
      raise EZSQLException.Create(SUpdateSQLNoResult);
    RowAccessor.FillFromFromResultSet(RefreshResultSet, FInsertColumns);
    RefreshResultSet.ResetCursor; //unlock handles
  end;
-Mark
marsupilami
Platinum Boarder
Platinum Boarder
Posts: 1918
Joined: 17.01.2011, 14:17

Re: Issue with RefreshCurrentRow with no primary key.

Post by marsupilami »

Hello Mark,

I applied your changes to the SVN. They will be copied to git tonight.

Best regards,

Jan
MJFShark
Expert Boarder
Expert Boarder
Posts: 211
Joined: 04.06.2020, 13:59

Re: Issue with RefreshCurrentRow with no primary key.

Post by MJFShark »

Hi Jan,

Thanks!

-Mark
Post Reply