ProDataSet: Records appended via COPY-DATASET not changes?

Posted by randallkharp on 15-Feb-2011 18:22

It appears that records appened to a ProDataSet (PDS) via COPY-DATASET are not considered changes to the target PDS, is that correct?

e.g.

1. Set TRACKING-CHANGES = TRUE for target PDS's buffers.

2. DATASET dsTarget:COPY-DATASET(DATASET dsSource:HANDLE, TRUE).  /* append mode */

3. DATASET dsChanges:GET-CHANGES(DATASET dsTarget:HANDLE).

Result: dsTarget contains new records from dsSource, but dsChanges contains no records - i.e. no changes tracked in dsTarget.

Ideas?

All Replies

Posted by danielStafford on 16-Feb-2011 16:54

You have set the row-state of the appended rows to ROW-CREATED.

Use the MARK-ROW-STATE method of the buffer handle.

Posted by randallkharp on 16-Feb-2011 19:09

I think that I may not be understanding your reply. Are you saying that I will have to query all the records (in multiple buffers) in the source PDS and MARK-ROW-STATE for each corresponding record in the target PDS?

If such is the case, why not forsake the COPY-DATASET method and programatically copy records from the source PDS to the target PDS, setting the ROW-STATE along the way?

In the end, I am visualizing a PDS in a tree. I want the user to visualize the effect of an operation - which adds more nodes to the tree (via records copied from a fetched dataset) - and then be able to reject those changes, restoring the visualized PDS to its original state. Naturally, if the records appended via COPY-DATASET aren't tracked as changes, I cannot reject them via REJECT-CHANGES. If I have to programmatically track changes on my own, so be it, but disappointed that not all changes to a PDS's buffers are tracked when TRACKING-CHANGES is on.

Posted by danielStafford on 16-Feb-2011 21:00

"If such is the case, why not forsake the COPY-DATASET method and programatically copy records from the source PDS to the target PDS, setting the ROW-STATE along the way?"

This seems reasonable. Do a CREATE and BUFFER-COPY TO (unique keys?), all while TRACKING-CHANGES (you won't have to set the ROW-STATE).

If the user likes the changes, save them, if not reject them.

Posted by Peter Judge on 17-Feb-2011 08:11

randallkharp wrote:

I think that I may not be understanding your reply. Are you saying that I will have to query all the records (in multiple buffers) in the source PDS and MARK-ROW-STATE for each corresponding record in the target PDS?

If such is the case, why not forsake the COPY-DATASET method and programatically copy records from the source PDS to the target PDS, setting the ROW-STATE along the way?

In the end, I am visualizing a PDS in a tree. I want the user to visualize the effect of an operation - which adds more nodes to the tree (via records copied from a fetched dataset) - and then be able to reject those changes, restoring the visualized PDS to its original state. Naturally, if the records appended via COPY-DATASET aren't tracked as changes, I cannot reject them via REJECT-CHANGES. If I have to programmatically track changes on my own, so be it, but disappointed that not all changes to a PDS's buffers are tracked when TRACKING-CHANGES is on.

I use CREATE-LIKE() and GET-CHANGES() for this, which works nicely (as below). However, this presumes that your set of changes are atomic/singular and that you don't slowly build up a set of data in the dsChanges PDS over time (as opposed to my approach which lets those changes be managed in the source PDS and plonked into the dsTarget in one operation). Not sure why you'd want that change state managed in 2 datasets though.

function EnableDatasetForUpdate returns logical (phDataset as handle):

    define variable iLoop   as integer no-undo.

    define variable hBuffer as handle  no-undo.

    do iLoop = 1 to phDataset:num-buffers:

        hBuffer = phDataset:get-buffer-handle(iLoop).

        hBuffer:table-handle:tracking-changes = true.

    end.

end function.

def temp-table tt no-undo before-table bTT

    field f1 as char

    field f2 as char

    .

define dataset ds1 for tt.

def var htarget as handle.

def var hbuf as handle.

EnableDatasetForUpdate(dataset ds1:handle).

DO transaction:

    create tt.

    tt.f1 = 'a'.

    tt.f2 = 'a'.

    create tt.

    tt.f1 = 'b'.

    tt.f2 = 'b'.

END.

create dataset htarget.

htarget:create-like(dataset ds1:handle).

htarget:get-changes(dataset ds1:handle).

MESSAGE

    htarget:get-buffer-handle(1):table-handle:has-records skip

    dataset ds1:get-buffer-handle(1):table-handle:has-records skip

    VIEW-AS ALERT-BOX INFO BUTTONS OK.

-- peter

Posted by Jeff Ledbetter on 17-Feb-2011 09:23

Peter,

I don't think that we managing the change state in two dataset.

Essentially, we have a local PDS which represents a subset of data visualized in a tree. What we are trying to accomplish is to have the user peform an action that essentially replaces the value of a node (PDS record) and all of it's children (child records in the PDS). This requires calling the server to get a new set of values that we want to copy into the local PDS as replacement values

It does not seem to unusal to me. If our approach is wrong, I welcome any feedback.

Jeff Ledbetter

Posted by Peter Judge on 17-Feb-2011 10:37

jeffledbetter wrote:

Peter,

I don't think that we managing the change state in two dataset.

Essentially, we have a local PDS which represents a subset of data visualized in a tree. What we are trying to accomplish is to have the user peform an action that essentially replaces the value of a node (PDS record) and all of it's children (child records in the PDS). This requires calling the server to get a new set of values that we want to copy into the local PDS as replacement values

It does not seem to unusal to me. If our approach is wrong, I welcome any feedback.

Jeff Ledbetter

Does not sound unusual to me either. My "dual state" statement was because I extrapolated Randall's post to mean something like this:

- user  does stuff

- code copies changes to PDS. No server commit yet.

- user does more stuff

- code copies changes to PDS. No server commit yet.

- user says 'commit' and the changes dataset goes across the wire

As opposed to

- user does stuff

- user does more stuff

- code copies changes to PDS.

- user says 'commit' and the changes dataset goes across the wire

-- peter

Posted by randallkharp on 17-Feb-2011 10:44

Thanks Daniel and Peter for some helpful thoughts.

I could see making a generic "copy with tracking" function or method that gets enables TRACKING-CHANGES for each buffer in the target PDS, then copies the source PDS records to the target PDS, e.g.

DO i = 1 to phDSsource:NUM-BUFFERS:

      

hSourceBuf = phDSsource:GET-BUFFER-HANDLE(i).

hTargetBuf = phdsTarget:GET-BUFFER-HANDLE(hSourceBuf:NAME).

hTargetBuf:TRACKING-CHANGES = TRUE.

hQry:SET-BUFFERS(hSourceBuf).
hQry:QUERY-PREPARE("for each " + hSourceBuf:NAME).
hQry:QUERY-OPEN().
hQry:GET-FIRST().

    

DO WHILE NOT hQry:QUERY-OFF-END:

hTargetBuf:BUFFER-CREATE().

hTargetBuf:BUFFER-COPY(hSourceBuf).

hQry:GET-NEXT().

END.

END. /* do i */

While this has been good for mental exercise, it's still disappointing to me that not all changes to a buffer are tracked when TRACKING-CHANGES is set.

Posted by Peter Judge on 17-Feb-2011 11:11

randallkharp wrote:

Thanks Daniel and Peter for some helpful thoughts.

I could see making a generic "copy with tracking" function or method that gets enables TRACKING-CHANGES for each buffer in the target PDS, then copies the source PDS records to the target PDS, e.g.

While this has been good for mental exercise, it's still disappointing to me that not all changes to a buffer are tracked when TRACKING-CHANGES is set.

It looks to work for me (in 10.2B03).

I've attached a .p which is a mod of the code I posted earlier. I've added code to the end that does what I think you want to do; it then generates a JSON file containing the contents of the changes dataset. Am I off the mark in the .P?

-- peter

Posted by randallkharp on 17-Feb-2011 11:49

pjudge wrote:

Am I off the mark in the .P?

-- peter

No - however the trick seems to be to track changes in the source dataset (even though I'm not really interested in what has "changed" there, since every record is a change).

If you run your .p without tracking changes in the source dataset (EnableDatasetForUpdate(dataset ds1:handle)), then there are no "changes" in the target dataset after the COPY-DATASET - even though the source records have been appended to the target dataset. Apparently COPY-DATASET means "copy the rows and the row-states from the source dataset".

I was misundertanding COPY-DATASET to be a "shortcut" for copying the records from one dataset to another - sort of an alias for a mass BUFFER-COPY. Now, I see that it is more of a "CARBON-COPY-DATASET", appending an exact image of rows and row-states to the target dataset.

Posted by Peter Judge on 17-Feb-2011 12:01

The help does indicate that that the before-table records are copied.

"

Note: If the source or target (but not both) ProDataSet has any before-table records, you can use COPY-DATASET on that ProDataSet. However, if append mode or replace mode is specified and the target ProDataSet has any before-table records, the AVM generates a run-time error.

"

I think the fact that the COPY-DATASET is such a sweeping copy is the reason I went for CREATE-LIKE() and GET-CHANGES(); but that was some time ago and I can barely remember what I had for breakfast

-- peter

This thread is closed