project BLF > class Persistence (Progress) > method WriteData

Description

Write the data to the database.
This takes care of the transfer of data from the class temp-tables to the real database tables.
It also takes care of the optimistic locking checkings (using t_i<table>).


Parameters


tDynRelinputtemp-tableDescription of the data to write.
ihClassinputhandleHandle to the class that is using the persistence layer. In most of the cases, this handle will be available in the preprocessor {&TARGETPROCEDURE}.
ihRowidConvertinputhandleHandle to the temp-table tFcRowidConvert.
icUserLogininputcharacter
oiReturnStatusoutputinteger


Internal usage


unused


program code (program1/progress.p)

&scoped-define TBF tBufferFields.thBufferField
&scoped-define TDF tBufferFields.thDestinationField
&scoped-define TIF tBufferFields.thIDestinationField

if transaction = no
then do:
    <M-42 run ErrorMessage
       (input  'No transaction was started before writing to the database.':U (icMessage), 
        input  '' (icArguments), 
        input  '' (icFieldName), 
        input  '' (icFieldValue), 
        input  '' (icRowid), 
        input  ? (ihClass)) in Progress>
    assign oiReturnStatus = -3.
    return.
end.

/* copy tDynRel into method data items that cannot be changed by other
   instances of this method (as started by ref.integrity programs) */
for each tDynRel on error undo, throw:
    assign viDynrelNum = viDynrelNum + 1
           vcDynrelTo[viDynrelNum] = tDynRel.tcFcTo
           vhDynrelBuffer[viDynrelNum] = tDynRel.thFcBuffer
           vhDynrelIbuffer[viDynrelNum] = tDynRel.thFcIBuffer.
end.

do viDynrelCount = 1 to viDynrelNum:

    assign vhRefInt = ?.

    /* ================================================================= */
    /*  First, take care that all buffer fields are known for this table */
    /* ================================================================= */
    <M-41 run UpdateBufferInfo
       (input  vcDynrelTo[viDynrelCount] (icTableName), 
        input  vhDynrelBuffer[viDynrelCount] (ihDestinationBuffer), 
        input  vhDynrelIbuffer[viDynrelCount] (ihIDestinationBuffer), 
        input  ihClass (ihClass), 
        output vhBuffer (ohBuffer), 
        output vhDummy (ohQuery), 
        output viFcReturnSuper (oiReturnStatus)) in Progress>
    if viFcReturnSuper <> 0
    then do:
        assign oiReturnStatus = viFcReturnSuper.
        return.
    end.
    
    /* ================================================================= */
    /*  Now, create the queries for retrieval of t and t_i data          */
    /* ================================================================= */
    create query vhTQuery in widget-pool "non-persistent".
    vhTQuery:forward-only = yes.
    vhTQuery:set-buffers(vhDynrelBuffer[viDynrelCount]).

    /* ================================================================= */
    /* delete records                                                    */
    /* ================================================================= */
    vhTQuery:query-prepare
        ("for each ":U + vhDynrelBuffer[viDynrelCount]:name +
         " where ":U + vhDynrelBuffer[viDynrelCount]:name + ".tc_status = 'D'":U).
    vhTQuery:query-open().
    vhTQuery:get-first().
    
    do while not vhTQuery:query-off-end :
    
        /* Check for optimistic lock */
        vhDynrelIbuffer[viDynrelCount]:find-unique ("where tc_rowid = '":U + vhDynrelBuffer[viDynrelCount]::tc_Rowid + "'":U) no-error.
        if not vhDynrelIbuffer[viDynrelCount]:available
        then do:
            <M-51 run ErrorMessage
               (input  'Invalid rowid ($1)':U (icMessage), 
                input  vhDynrelBuffer[viDynrelCount]::tc_Rowid (icArguments), 
                input  vhDynrelBuffer[viDynrelCount]:name (icFieldName), 
                input  '' (icFieldValue), 
                input  vhDynrelBuffer[viDynrelCount]::tc_Rowid (icRowid), 
                input  ihClass (ihClass)) in Progress>
            assign oiReturnStatus = -3.
            
            if vhRefInt <> ?
            then do:
                delete procedure vhRefInt.
                assign vhRefInt = ?.
            end.
            
            return.
        end.
        
        if vlOptLock
        then vhBuffer:find-by-rowid(to-rowid(string(vhDynrelBuffer[viDynrelCount]::tc_Rowid)), no-lock) no-error.
        else do:
            do viFcCount1 = 1 to 5:
                vhBuffer:find-by-rowid(to-rowid(string(vhDynrelBuffer[viDynrelCount]::tc_Rowid)),
                                        exclusive-lock, no-wait) no-error.
                if vhBuffer:locked
                then pause 3 no-message.
                else leave.
            end.
            if vhBuffer:locked
            then do:
                <M-43 run ErrorMessage
                   (input  #T-41'Update failed: database record stays locked.':255(90)T-41# (icMessage), 
                    input  '' (icArguments), 
                    input  vhBuffer:table (icFieldName), 
                    input  '' (icFieldValue), 
                    input  vhDynrelBuffer[viDynrelCount]::tc_Rowid (icRowid), 
                    input  ihClass (ihClass)) in Progress>

                assign oiReturnStatus = -3.

                if vhRefInt <> ?
                then do:
                    delete procedure vhRefInt.
                    assign vhRefInt = ?.
                end.

                return.
            end.
        end.

        if not vhBuffer:available
        then do:
            /* optimistic lock, record is deleted */
            assign vlOptLock = yes.
            <M-44 run ErrorMessage
               (input  #T-42'A detail line you tried to delete was already deleted by another user.':255(84)T-42# (icMessage), 
                input  '' (icArguments), 
                input  vcDynrelTo[viDynrelCount] (icFieldName), 
                input  '' (icFieldValue), 
                input  string(vhDynrelBuffer[viDynrelCount]::tc_Rowid) (icRowid), 
                input  ihClass (ihClass)) in Progress>

            vhTQuery:get-next ().
            next.

        end.
        
        for each tBufferFields where
                 tBufferFields.thTempBuffer = vhDynrelBuffer[viDynrelCount] 
                 on error undo, throw:
            if {&TDF}:help = ?
            or ({&TDF}:help = "OL-C":U and {&TDF}:buffer-value <> {&TIF}:buffer-value)
            then do:
                if {&TIF}:buffer-value <> {&TBF}:buffer-value
                then do:
                    /* optimistic lock, record is changed */
                    assign vlOptLock = yes.
                    <M-45 run ErrorMessage
                       (input  #T-43'This field was changed from $1 to $2 by another user.':255(82)T-43# (icMessage), 
                        input  substitute ('&1' + chr(2) + '&2',{&TIF}:buffer-value,{&TBF}:buffer-value) (icArguments), 
                        input  vcDynrelTo[viDynrelCount] + '.':U + {&TDF}:name (icFieldName), 
                        input  string({&TDF}:buffer-value) (icFieldValue), 
                        input  string(vhDynrelBuffer[viDynrelCount]::tc_Rowid) (icRowid), 
                        input  ihClass (ihClass)) in Progress>
                end.
            end.
            else if {&TDF}:buffer-value = {&TIF}:buffer-value
            then assign {&TDF}:buffer-value = {&TBF}:buffer-value.
        end.
        
        if search ("ref_int/dc_":U + lc(vcDynrelTo[viDynrelCount]) + ".r":U) <> ?
        or search ("ref_int/dc_":U + lc(vcDynrelTo[viDynrelCount]) + ".p":U) <> ?
        then do:
            if vhRefInt = ?
            then run value ("ref_int/dc_":U + lc(vcDynrelTo[viDynrelCount]) + ".p":U)
                     persistent set vhRefInt.
            run gipr_RefInt in vhRefInt
               (input vhDynrelBuffer[viDynrelCount],
                input ihClass,
                input {&TARGETPROCEDURE},
                input icUserLogin,
                output viFcReturnSuper).

            if viFcReturnSuper < 0
            then do:
                assign oiReturnStatus = viFcReturnSuper.
                
                if vhRefInt <> ?
                then do:
                    delete procedure vhRefInt.
                    assign vhRefInt = ?.
                end.
                
                return.
            end.
        end.

        if not vlOptLock
        then do:
            publish "Logging.DatabaseAccess"
                   ("delete ":U + vcDynrelTo[viDynrelCount], vhBuffer).
            vhBuffer:buffer-delete().
        end.
    
        vhTQuery:get-next ().
    end.
    
    vhTQuery:query-close().
    
    if vhRefInt <> ?
    then do:
        delete procedure vhRefInt.
        assign vhRefInt = ?.
    end.
    
    /* ================================================================= */
    /* create or update records (update first, create last)              */
    /* ================================================================= */
    vhTQuery:query-prepare
        ("for each ":U + vhDynrelBuffer[viDynrelCount]:name +
         " where ":U + vhDynrelBuffer[viDynrelCount]:name + ".tc_status = 'N'":U +
         " or ":U + vhDynrelBuffer[viDynrelCount]:name + ".tc_status = 'C'":U +
         " by ":U + vhDynrelBuffer[viDynrelCount]:name + ".tc_status":U).
    vhTQuery:query-open().
    vhTQuery:get-first().
    
    do while not vhTQuery:query-off-end :
    
        if vhDynrelBuffer[viDynrelCount]::tc_Status = "N":U
        then do:
            if vlOptLock = no
            then vhBuffer:buffer-create().
        end.
        else do:
            /* Check for optimistic lock */
            vhDynrelIbuffer[viDynrelCount]:find-unique ("where tc_rowid = '":U + vhDynrelBuffer[viDynrelCount]::tc_Rowid + "'":U) no-error.
            if not vhDynrelIbuffer[viDynrelCount]:available
            then do:
                <M-52 run ErrorMessage
                   (input  'Invalid rowid ($1)':U (icMessage), 
                    input  vhDynrelBuffer[viDynrelCount]::tc_Rowid (icArguments), 
                    input  vhDynrelBuffer[viDynrelCount]:name (icFieldName), 
                    input  '' (icFieldValue), 
                    input  vhDynrelBuffer[viDynrelCount]::tc_Rowid (icRowid), 
                    input  ihClass (ihClass)) in Progress>
                assign oiReturnStatus = -3.                
                return.
            end.
            
            if vlOptLock
            then vhBuffer:find-by-rowid(to-rowid(string(vhDynrelBuffer[viDynrelCount]::tc_Rowid)), no-lock) no-error.
            else do:
                do viFcCount1 = 1 to 5:
                    vhBuffer:find-by-rowid(to-rowid(string(vhDynrelBuffer[viDynrelCount]::tc_Rowid)),
                                            exclusive-lock, no-wait) no-error.
                    if vhBuffer:locked
                    then pause 3 no-message.
                    else leave.
                end.
                if vhBuffer:locked
                then do:
                    <M-46 run ErrorMessage
                       (input  #T-44'Update failed: database record stays locked.':255(90)T-44# (icMessage), 
                        input  '' (icArguments), 
                        input  vhBuffer:table (icFieldName), 
                        input  '' (icFieldValue), 
                        input  vhDynrelBuffer[viDynrelCount]::tc_Rowid (icRowid), 
                        input  ihClass (ihClass)) in Progress>
                    assign oiReturnStatus = -3.
                    return.
                end.
            end.

            if vhBuffer:available
            then for each tBufferFields where
                          tBufferFields.thTempBuffer = vhDynrelBuffer[viDynrelCount] 
                          on error undo, throw:
                if {&TDF}:help = ?
                or ({&TDF}:help = "OL-C":U and {&TDF}:buffer-value <> {&TIF}:buffer-value)
                then do:
                    if {&TIF}:buffer-value <> {&TBF}:buffer-value
                    then do:
                        /* optimistic lock, record is changed */
                        assign vlOptLock = yes.
                        <M-47 run ErrorMessage
                           (input  #T-45'This field was changed from $1 to $2 by another user.':255(82)T-45# (icMessage), 
                            input  substitute ('&1' + chr(2) + '&2',{&TIF}:buffer-value,{&TBF}:buffer-value) (icArguments), 
                            input  vcDynrelTo[viDynrelCount] + '.':U + {&TDF}:name (icFieldName), 
                            input  string({&TDF}:buffer-value) (icFieldValue), 
                            input  string(vhDynrelBuffer[viDynrelCount]::tc_Rowid) (icRowid), 
                            input  ihClass (ihClass)) in Progress>
                    end.
                end.
                else if {&TDF}:buffer-value = {&TIF}:buffer-value
                then assign {&TDF}:buffer-value = {&TBF}:buffer-value.
            end.
            else do:
                /* optimistic lock, record is deleted */
                assign vlOptLock = yes.
                <M-48 run ErrorMessage
                   (input  #T-46'A detail line you tried to change was deleted by another user.':255(83)T-46# (icMessage), 
                    input  '' (icArguments), 
                    input  vcDynrelTo[viDynrelCount] (icFieldName), 
                    input  '' (icFieldValue), 
                    input  string(vhDynrelBuffer[viDynrelCount]::tc_Rowid) (icRowid), 
                    input  ihClass (ihClass)) in Progress>
            end.
        end.

        if not vlOptLock
        then do:
            vhBuffer:buffer-copy(vhDynrelBuffer[viDynrelCount]) no-error.
            if error-status:error
            then do:
                assign vlOptLock = yes.
                if error-status:get-message(1) matches "*(132)":U
                then do:
                    assign vcTemp = error-status:get-message (1)
                           vcWork = #T-36'A detail line you tried to create was already created by another user.':255(85)T-36# + " - ":U + vcTemp.
                    <M-49 run ErrorMessage
                       (input  vcWork (icMessage), 
                        input  '' (icArguments), 
                        input  vcDynrelTo[viDynrelCount] (icFieldName), 
                        input  '' (icFieldValue), 
                        input  string(vhDynrelBuffer[viDynrelCount]::tc_Rowid) (icRowid), 
                        input  ihClass (ihClass)) in Progress>
                    leave.
                end.
                else do viFcCount1 = 1 to error-status:num-messages:
                    <M-50 run ErrorMessage
                       (input  error-status:get-message(viFcCount1) (icMessage), 
                        input  '' (icArguments), 
                        input  vcDynrelTo[viDynrelCount] (icFieldName), 
                        input  '' (icFieldValue), 
                        input  string(vhDynrelBuffer[viDynrelCount]::tc_Rowid) (icRowid), 
                        input  ihClass (ihClass)) in Progress>
                end.
            end.

            if vhDynrelBuffer[viDynrelCount]::tc_Status = "N":U
            then do:
                ihRowidConvert:buffer-create().
                assign ihRowidConvert::tcFcOldRowid = vhDynrelBuffer[viDynrelCount]::tc_Rowid
                       ihRowidConvert::tcFcNewRowid = string(vhBuffer:rowid).
                ihRowidConvert:buffer-release().
            end.
            
            publish "Logging.DatabaseAccess"
                   ((if vhDynrelBuffer[viDynrelCount]::tc_Status = "N":U then "create " else "update ") + vcDynrelTo[viDynrelCount], vhBuffer).
        end.
            
        vhBuffer:buffer-release().    
        vhTQuery:get-next ().
    end.
    
    vhTQuery:query-close().
    delete object vhTQuery.
    vhTQuery = ?.
end.

if vlOptLock
then assign oiReturnStatus = -2.

finally:
    if vhTQuery <> ?
    then do:
        vhTQuery:query-close().
        delete object vhTQuery.
    end.
end finally.