The ai_unpacked file contained a lot of details, but did not contain the string value "bpaytrancode" and therefore it was no help at all.
The ai scan verbose output won't contain the table name. It contains a summary of the change notes. Let's look at a simple example (from 11.7.16).
I created a copy of the sports database. I created four AI areas and two new Type 2 areas:
Code:
$ cat add.st
d "state":20,128;8 .
d "state_idx":21,128;8 .
a .
a .
a .
a .
Then I moved the state table into area 20 and its index into area 21, enabled AI, and switched to a new AI extent.
I ran the following code:
Code:
find first state.
display recid( state ).
delete state.
In this case, the recid of the deleted record (Alaska) was 1537. We'll come back to that later.
Then I ran rfutil ai scan verbose on the extent with the deletion notes. Here is the output.
Code:
Trid: 0 code = RL_INMEM version = 3 (12528)
Trid: 0 dbkey = 0 update counter = 0 (12530)
Trid: 0 code = RL_LSTMOD version = 2 (12528)
Trid: 0 area = 6 dbkey = 32 update counter = 27 (12529)
Trid: 402 Wed Nov 27 14:27:20 2024. (2598)
Trid: 402 User Id: rob (12531)
Trid: 402 code = RL_TBGN version = 1 (12528)
Trid: 402 dbkey = 0 update counter = 0 (12530)
Trid: 402 code = RL_CXREM version = 2 (12528)
Trid: 402 area = 21 dbkey = 1536 update counter = 54 (12529)
Trid: 402 code = RL_RMDEL version = 2 (12528)
Trid: 402 area = 20 dbkey = 1536 update counter = 53 (12529)
Trid: 402 code = RL_RMCR version = 2 (12528)
Trid: 402 area = 20 dbkey = 1536 update counter = 54 (12529)
Trid: 402 Wed Nov 27 14:27:20 2024. (2598)
Trid: 402 code = RL_TEND version = 1 (12528)
Trid: 402 dbkey = 0 update counter = 0 (12530)
7 notes were processed. (1634)
0 in-flight transactions. (3785)
1 transactions were started. (1635)
1 transactions were completed. (11138)
At the end of the .ai file, 0 transactions were still active. (1636)
"Trid: <n>" is transaction ID. In this case, my changes happened in TrId 402.
The "code=RL_*" tokens show the type of AI note being processed.
When a record is deleted from a table, you will see AI notes like the following:
- Transaction begin (RL_TBGN)
- Delete index entry for the record (RL_CXREM)
- There will be one of these notes for each index defined on the table. In this case, the state table has one index so there is one RL_CXREM note.
- Delete the record (RL_RMDEL)
- Transaction end (RL_TEND)
It could look more complicated than it does in this very simple example, e.g. if the table has delete triggers.
Here is what we see in the notes, step by step:
Trid:
402 Wed Nov 27 14:27:20 2024. (2598)
Trid: 402 User Id:
rob (12531)
Trid: 402 code =
RL_TBGN version = 1 (12528)
Trid: 402 dbkey = 0 update counter = 0 (12530)
Translation: User "rob" started a transaction with Trid 402 at time stamp Wed Nov 27 14:27:20 2024.
Trid:
402 code =
RL_CXREM version = 2 (12528)
Trid: 402 area =
21 dbkey =
1536 update counter =
54 (12529)
This same transaction performed an index entry deletion (RM_CXREM) in the index block whose logical address is dbkey 1536 in storage area 21 (state_idx). This block write changed the block's update counter value to 54.
Trid:
402 code =
RL_RMDEL version = 2 (12528)
Trid: 402 area =
20 dbkey =
1536 update counter =
53 (12529)
This same transaction deleted a record fragment (RM_RMDEL) in the record block whose logical address is dbkey 1536 in storage area 20 (state). This block write changed the block's update counter value to 53.
Trid:
402 code =
RL_RMCR version = 2 (12528)
Trid: 402 area =
20 dbkey =
1536 update counter =
54 (12529)
This same transaction created a record fragment (RM_RMCR) in the record block whose logical address is dbkey 1536 in storage area 20 (state). This block write changed the block's update counter value to 54.
I
think this note is for the creation of a rowid placeholder in the block, to prevent any other transaction from creating a new record fragment there with recid 1537, in case my transaction rolled back and the deleted fragment needed to be recreated.
Trid:
402 Wed Nov 27 14:27:20 2024. (2598)
Trid: 402 code =
RL_TEND version = 1 (12528)
Trid: 402 dbkey = 0 update counter = 0 (12530)
Finally, this transaction with Trid 402 ended at time stamp Wed Nov 27 14:27:20 2024.
The takeaway here is that the single logical operation of deleting one record is made up of several parts (notes). Some of these note types are for housekeeping like RL_TBGN and RL_TEND; transaction begin and end. Some of these note types (RL_CXREM, RL_RMDEL, RL_RMCR) describe physical operations on database
blocks (not on logical entities like tables or indexes), so they don't reference a table or index number or name. In this case, my objects were in Type 2 areas and so each block in a data area belongs to one and only one storage object, but that wouldn't be the case in a Type 1 area.
In my example, I knew the recid of the deleted record in advance, because I displayed it before deleting the record. In your case, you would need an earlier copy of the database that still contains the record, so you could find the record in that copy and then display the recid. You need this because the RL_RMDEL note provides the area number and block address (dbkey). You can derive the dbkey of the record block if you know the recid of a record fragment in that block and the RPB (record per block) of the storage area. In my case:
recid of deleted record = 1537
RPB of area 20 = 128
dbkey = recid - (recid modulo RPB) = 1537 - (1537 modulo 128) = 1537 - 1 = 1536.
Once you have the area number and dbkey, you can grep through your ai scan verbose output for a line with "code = RL_RMDEL" followed by a line with "area = <your area number>" and "dbkey = <your dbkey>". From those lines, you will have the Trid of the transaction that deleted the record. Then by further grepping for "Trid: <your trid>" and "RL_TBGN" and "RL_TEND", you will know the window of time in which the transaction happened and the user name (though unfortunately not the user number) of the user who performed the action.
If desired, you can compare that info against your database log for more info like when they logged in and out that day, which terminal or remote IP address they used, etc. And you can look further through the ai scan verbose logs to see any other changes they may have made in other transactions. I hope this helps.