project BLF > class BQueryCache > method RunQuery

Description

This method implements the standard interface of API queries for API query procedures.
This method will be called from the generated code for query procedures and not directly from the client.


Parameters


icClassNameinputcharacter
icMethodNameinputcharacter
icRangeinputcharacter
icRowidinputcharacter
iiRowNuminputinteger
iiNumberinputinteger
icSortColumnsinputcharacter
ilCountOnlyinputlogical
ilForwardReadinputlogical
iiMaximumBrowseRecordsToCountinputinteger
tFilterinputtemp-table
oiCountoutputinteger
olEndOfQueryoutputlogical
ihResultSetBufferinputhandle
oiReturnStatusoutputintegerReturn status of the method.


Internal usage


unused


program code (program1/bquerycache.p)

olEndOfQuery = yes.

if icRowid  = ? then icRowid  = "".
if iiRowNum = ? then iiRowNum = 0.
if iiNumber = ? then iiNumber = 0.

if icRowid = ""
and iiNumber = 0
then do:
    /* ================================================================= */
    /* when requested to return a full dataset, do not create a cache.   */
    /* Also do not look if any cache exists.                             */
    /* ================================================================= */
    <M-65 run BusinessClassActions
       (input  icClassName (icClassShortname), 
        input  'START+OPEN' (icAction), 
        input  no (ilSubtransaction), 
        input-output viQueryClassOC (biClassOpenCount), 
        input-output vhQueryClass (bhClassInstanceHandle), 
        input-output viQueryClassID (biClassInstanceId), 
        input  '' (icDraftReference), 
        input  '' (icUserDefinedContext), 
        output viFcReturnSuper (oiReturnStatus)) in BQueryCache>
    if viFcReturnSuper <> 0
    then oiReturnStatus = viFcReturnSuper.
    if viFcReturnSuper < 0
    then return.
    
    run value(icMethodName) in vhQueryClass
       (input dataset tFilter,
        output dataset-handle vhQueryDataset by-reference,
        output viFcReturnSuper).

    if viFcReturnSuper <> 0
    then oiReturnStatus = viFcReturnSuper.
    if viFcReturnSuper < 0
    then do:
        <M-35 run BusinessClassActions
           (input  icClassName (icClassShortname), 
            input  'CLOSE+STOP' (icAction), 
            input  no (ilSubtransaction), 
            input-output viQueryClassOC (biClassOpenCount), 
            input-output vhQueryClass (bhClassInstanceHandle), 
            input-output viQueryClassID (biClassInstanceId), 
            input  '' (icDraftReference), 
            input  '' (icUserDefinedContext), 
            output viFcReturnSuper (oiReturnStatus)) in BQueryCache>
        return.
    end.
    
    /* ================================================================= */
    /* Count records in the resultset, or copy requested data            */
    /* into the output resultset (ihResultSetBuffer).                    */
    /* ================================================================= */
    vhQueryTableBuffer = vhQueryDataset:get-top-buffer(1).
    create query vhQuery in widget-pool "non-persistent".
    vhQuery:forward-only = yes.
    vhQuery:set-buffers(vhQueryTableBuffer).
    
    /* ================================================================= */
    /* Apply sorting.                                                    */
    /* ================================================================= */
    if ilCountOnly = no
    and num-entries (icSortColumns,"|") = 2
    then do viSortNum = 1 to vhQueryTableBuffer:num-fields:
        vhSortField = vhQueryTableBuffer:buffer-field(viSortNum).
        if substring(vhSortField:name,3,-1,"CHARACTER") = entry(1,icSortColumns,"|")
        then do:
            vhQuery:query-prepare ("for each " + vhQueryTableBuffer:name +
                                   " by " + vhSortField:name +
                                  (if entry(2,icSortColumns,"|") = "D" then " descending by ti_Sequence descending" else " by ti_Sequence")).
            vhQuery:query-open().
            vhQuery:get-first().
            do while not vhQuery:query-off-end:
                viSortCount = viSortCount + 1.
                vhQueryTableBuffer::ti_Sequence = viSortCount.
                vhQuery:get-next().
            end.
            vhQuery:query-close().
            leave.
        end.
    end.
            
    vhQuery:query-prepare ("for each " + vhQueryTableBuffer:name + " by " + vhQueryTableBuffer:name + ".ti_Sequence").
    vhQuery:query-open().
    do while true:
        vhQuery:get-next().
        if vhQuery:query-off-end then leave.
        if ilCountOnly
        then oiCount = oiCount + 1.
        else do:
            ihResultSetBuffer:buffer-create().
            ihResultSetBuffer:raw-transfer(false,vhQueryTableBuffer).
            ihResultSetBuffer:buffer-release().
        end.
    end.
    vhQuery:query-close().
    delete object vhQuery.
    
    <M-73 run BusinessClassActions
       (input  icClassName (icClassShortname), 
        input  'CLOSE+STOP' (icAction), 
        input  no (ilSubtransaction), 
        input-output viQueryClassOC (biClassOpenCount), 
        input-output vhQueryClass (bhClassInstanceHandle), 
        input-output viQueryClassID (biClassInstanceId), 
        input  '' (icDraftReference), 
        input  '' (icUserDefinedContext), 
        output viFcReturnSuper (oiReturnStatus)) in BQueryCache>
end.
else do:
    <M-79 run StartPersistence
       (output vhPL (ohPersistence), 
        output viFcReturnSuper (oiReturnStatus)) in BQueryCache>
    if viFcReturnSuper <> 0
    then oiReturnStatus = viFcReturnSuper.
    if viFcReturnSuper < 0
    then return.
    
    /* ================================================================= */
    /* Calculate a unique key to identify the current search.            */
    /* ================================================================= */
    vpSearchKeyData = icClassName + "." + icMethodName + "." + string(viSessionID).
    vaSearchKey = md5-digest(vpSearchKeyData).
    vcSearchKey = base64-encode(vaSearchKey).
    vcSearchQuery = "for each QueryCache where QueryCache.SearchKey = '" + vcSearchKey + "'".

    if ilCountOnly
    then LoopForCount: do while true:
    
        pause 3 no-message.
        
        vhFcComponent = vhPL.
        <M-97 run ReadDirect
           (input  'QueryCache' (icTableName), 
            input  vcSearchQuery (icPrepare), 
            input  'RecordCount' (icFieldList), 
            output vcrc (ocValueList), 
            input  {&TARGETPROCEDURE} (ihClass), 
            output viFcReturnSuper (oiReturnStatus)) in persistence>
        viTo = integer(vcrc) no-error.
        if viFcReturnSuper >= 0
        and viTo >= 0
        then do:
            oiCount = viTo.
            leave LoopForCount.
        end.
        else do:
            /* ================================================================= */
            /* When no resultset found, another process is still creating it.    */
            /* ================================================================= */
            if viCountLoop > 20
            then leave LoopForCount.    /* waited more than enough, just return a zero count */
            
            /* try again */
            viCountLoop = viCountLoop + 1.
            next LoopForCount.
        end.
    end.
    else do:
    
        if icRowid = ""
        and ilForwardRead = yes
        then do:
            /* any existing cache will be overridden */
            vlGetData = yes.
            vhFcComponent = vhPL.
            <M-64 run WriteDirect
               (input  'QueryCache' (icTableName), 
                input  vcSearchQuery (icPrepare), 
                input  'RecordCount' (icFieldList), 
                input  'i' (icFieldListDataTypes), 
                input  '-1' (icAbsolute), 
                input  '' (icIncremental), 
                input  {&TARGETPROCEDURE} (ihClass), 
                input  vcUserLogin (icUserLogin), 
                output viFcReturnSuper (oiReturnStatus)) in persistence>
            /* ignore errors */
        end.

        /* ================================================================= */
        /* Load the description of the query resultset into memory.          */
        /* Not the resultset data !                                          */
        /* ================================================================= */
        vcSearchQuery = "for each QueryCache where QueryCache.SearchKey = '" + vcSearchKey + "'".
        <M-22 run DataLoad
           (input  '' (icRowids), 
            input  '' (icPkeys), 
            input  '' (icObjectIds), 
            input  vcSearchQuery (icFreeform), 
            input  no (ilKeepPrevious), 
            output viFcReturnSuper (oiReturnStatus)) in BQueryCache>
        
        if viFcReturnSuper = -4
        then do:
            /* ================================================================= */
            /* When no resultset found, create it.                               */
            /* ================================================================= */
            <M-23 run DataNew  (output viFcReturnSuper (oiReturnStatus)) in BQueryCache>
            if viFcReturnSuper <> 0
            then oiReturnStatus = viFcReturnSuper.
            if viFcReturnSuper < 0
            then return.
            vlGetData = yes.
            vhFcComponent = vhPL.
            assign tQueryCache.SearchKey   = vcSearchKey
                   tQueryCache.Instance_ID = <M-45 GetNextValue  (input  'InstanceNumber' (icSequence)) in persistence>.
        end.
        else do:
            if viFcReturnSuper <> 0
            then oiReturnStatus = viFcReturnSuper.
            if viFcReturnSuper < 0
            then return.
            
            find first tQueryCache.
            
            if vlGetData
            then do:
                assign tQueryCache.RecordCount = 0
                       tQueryCache.tc_Status   = "C".
                vhFcComponent = vhPL.
                <M-75 run DeleteInstance
                   (input  tQueryCache.Instance_ID (iiInstanceID), 
                    input  {&TARGETPROCEDURE} (ihClass), 
                    input  'BQueryCache' (icClassName), 
                    output viFcReturnSuper (oiReturnStatus)) in persistence>
                if viFcReturnSuper <> 0
                then oiReturnStatus = viFcReturnSuper.
                if viFcReturnSuper < 0
                then return.
            end.
        end.

        if vlGetData
        then do:
            <M-82 run BusinessClassActions
               (input  icClassName (icClassShortname), 
                input  'START+OPEN' (icAction), 
                input  no (ilSubtransaction), 
                input-output viQueryClassOC (biClassOpenCount), 
                input-output vhQueryClass (bhClassInstanceHandle), 
                input-output viQueryClassID (biClassInstanceId), 
                input  '' (icDraftReference), 
                input  '' (icUserDefinedContext), 
                output viFcReturnSuper (oiReturnStatus)) in BQueryCache>
            if viFcReturnSuper <> 0
            then oiReturnStatus = viFcReturnSuper.
            if viFcReturnSuper < 0
            then return.
            
            run value(icMethodName) in vhQueryClass
               (input dataset tFilter,
                output dataset-handle vhQueryDataset by-reference,
                output viFcReturnSuper).
            if viFcReturnSuper <> 0
            then oiReturnStatus = viFcReturnSuper.
            if viFcReturnSuper < 0
            then do:
                <M-53 run BusinessClassActions
                   (input  icClassName (icClassShortname), 
                    input  'CLOSE+STOP' (icAction), 
                    input  no (ilSubtransaction), 
                    input-output viQueryClassOC (biClassOpenCount), 
                    input-output vhQueryClass (bhClassInstanceHandle), 
                    input-output viQueryClassID (biClassInstanceId), 
                    input  '' (icDraftReference), 
                    input  '' (icUserDefinedContext), 
                    output viCountLoop (oiReturnStatus)) in BQueryCache>
                return.
            end.
    
            /* ================================================================= */
            /* Count records in the resultset, and copy requested data           */
            /* into the output resultset (ihResultSetBuffer).                    */
            /* ================================================================= */
            vhQueryTableBuffer = vhQueryDataset:get-top-buffer(1).
            create query vhQuery in widget-pool "non-persistent".
            vhQuery:set-buffers(vhQueryTableBuffer).
            
            /* ================================================================= */
            /* Apply sorting.                                                    */
            /* ================================================================= */
            if num-entries (icSortColumns,"|") = 2
            then do viSortNum = 1 to vhQueryTableBuffer:num-fields:
                vhSortField = vhQueryTableBuffer:buffer-field(viSortNum).
                if substring(vhSortField:name,3,-1,"CHARACTER") = entry(1,icSortColumns,"|")
                then do:
                    vhQuery:query-prepare ("for each " + vhQueryTableBuffer:name +
                                           " by " + vhSortField:name +
                                          (if entry(2,icSortColumns,"|") = "D" then " descending by ti_Sequence descending" else " by ti_Sequence")).
                    vhQuery:query-open().
                    vhQuery:get-first().
                    do while not vhQuery:query-off-end:
                        viSortCount = viSortCount + 1.
                        vhQueryTableBuffer::ti_Sequence = viSortCount.
                        vhQuery:get-next().
                    end.
                    vhQuery:query-close().
                    leave.
                end.
            end.
            
            if  iiRowNum = 0
            and icRowid <> ""
            then do:
                vhQuery:query-prepare ("for each " + vhQueryTableBuffer:name
                                       + " where " + vhQueryTableBuffer:name + ".tc_Rowid = '" + icRowid + "'").
                vhQuery:query-open().
                vhQuery:get-first().
                if not vhQuery:query-off-end
                then iiRowNum = vhQueryTableBuffer::ti_Sequence.
                vhQuery:query-close().
            end.
            
            if  iiRowNum = 0
            and icRowid  = ""
            and ilForwardRead = no
            then do:
                vhQuery:query-prepare ("for each " + vhQueryTableBuffer:name
                                          + " by " + vhQueryTableBuffer:name + ".ti_Sequence descending").
                vhQuery:query-open().
                vhQuery:get-first().
                if not vhQuery:query-off-end
                then iiRowNum = vhQueryTableBuffer::ti_Sequence + 1.
                vhQuery:query-close().
            end.
            
            if ilForwardRead
            then assign viFrom = iiRowNum
                        vito   = (if iiNumber = 0 then 999999 else iiRowNum + iiNumber + 1).
            else assign viFrom = (if iiNumber = 0 then 0      else iiRowNum - iiNumber - 1)
                        vito   = iiRowNum.
            
            vhQuery:query-prepare ("for each " + vhQueryTableBuffer:name + " by " + vhQueryTableBuffer:name + ".ti_Sequence").
            vhQuery:query-open().
            do while true:
                vhQuery:get-next().
                if vhQuery:query-off-end then leave.
                tQueryCache.RecordCount = tQueryCache.RecordCount + 1.
                if  vhQueryTableBuffer::ti_Sequence > viFrom
                and vhQueryTableBuffer::ti_Sequence < viTo
                then do:
                    ihResultSetBuffer:buffer-create().
                    ihResultSetBuffer:raw-transfer(false,vhQueryTableBuffer).
                    ihResultSetBuffer:buffer-release().
                end.
            end.
            vhQuery:query-close().
            delete object vhQuery.
            
            if (ilForwardRead = yes and viTo <= tQueryCache.RecordCount)
            or (ilForwardRead = no  and viFrom > 0)
            then olEndOfQuery = no.
            
            /* ================================================================= */
            /* Save the resultset.                                               */
            /* ================================================================= */
            vhFcComponent = vhPL.
            <M-48 run SaveInstance
               (input  {&TARGETPROCEDURE} (ihClass), 
                input  tQueryCache.Instance_ID (iiInstanceID), 
                input  vhQueryDataset (ihInstanceData), 
                input  'BQueryCache' (icClassName), 
                output viFcReturnSuper (oiReturnStatus)) in persistence>
            
            /* data does not need validation or additional updates */
            vlFcDataValidated = true.
            
            <M-55 run DataSave  (output viFcReturnSuper (oiReturnStatus)) in BQueryCache>
            
            <M-6 run BusinessClassActions
               (input  icClassName (icClassShortname), 
                input  'CLOSE+STOP' (icAction), 
                input  no (ilSubtransaction), 
                input-output viQueryClassOC (biClassOpenCount), 
                input-output vhQueryClass (bhClassInstanceHandle), 
                input-output viQueryClassID (biClassInstanceId), 
                input  '' (icDraftReference), 
                input  '' (icUserDefinedContext), 
                output viCountLoop (oiReturnStatus)) in BQueryCache>
    
            if viFcReturnSuper <> 0
            then oiReturnStatus = viFcReturnSuper.
            if viFcReturnSuper < 0
            then return.
        end.    /* vlgetdata = yes */
        else do:
            /* ================================================================= */
            /* Load the resultset data.                                          */
            /* ================================================================= */
            create temp-table vhCacheDataTable in widget-pool "non-persistent".
            vhCacheDataTable:create-like(ihResultSetBuffer).
            vhCacheDataTable:temp-table-prepare(ihResultSetBuffer:table).
            vhCacheDataTableBuffer = vhCacheDataTable:default-buffer-handle.
            create dataset vhCacheDataDataset in widget-pool "non-persistent".
            vhCacheDataDataset:name = ihResultSetBuffer:table.
            vhCacheDataDataset:set-buffers(vhCacheDataTableBuffer).
    
            vhFcComponent = vhPL.
            <M-32 run LoadInstance
               (input  {&TARGETPROCEDURE} (ihClass), 
                input  tQueryCache.Instance_ID (iiInstanceID), 
                input  vhCacheDataDataset (ihInstanceData), 
                input  'BQueryCache' (icClassName), 
                output viCountLoop (oiDraftInstanceId), 
                output viFcReturnSuper (oiReturnStatus)) in persistence>
            if viFcReturnSuper <> 0
            then oiReturnStatus = viFcReturnSuper.
            if viFcReturnSuper < 0
            then do:
                delete object vhCacheDataDataset.
                return.
            end.
    
            create query vhQuery in widget-pool "non-persistent".
            vhQuery:forward-only = yes.
            vhQuery:set-buffers(vhCacheDataTableBuffer).
    
            if  iiRowNum = 0
            and icRowid <> ""
            then do:
                vhQuery:query-prepare ("for each " + vhCacheDataTableBuffer:name
                                       + " where " + vhCacheDataTableBuffer:name + ".tc_Rowid = '" + icRowid + "'").
                vhQuery:query-open().
                vhQuery:get-first().
                if not vhQuery:query-off-end
                then iiRowNum = vhCacheDataTableBuffer::ti_Sequence.
                vhQuery:query-close().
            end.
            
            if ilForwardRead
            then assign viFrom = iiRowNum
                        vito   = (if iiNumber = 0 then 999999 else iiRowNum + iiNumber + 1).
            else do:
                 if iiRowNum = 0 then iiRowNum = tQueryCache.RecordCount + 1.
                 assign viFrom = (if iiNumber = 0 then 0      else iiRowNum - iiNumber - 1)
                        vito   = iiRowNum.
            end.
            
            vhQuery:query-prepare ("for each " + vhCacheDataTableBuffer:name
                                   + " where " + vhCacheDataTableBuffer:name + ".ti_Sequence > " + string(viFrom)
                                     + " and " + vhCacheDataTableBuffer:name + ".ti_Sequence < " + string(viTo)
                                      + " by " + vhCacheDataTableBuffer:name + ".ti_Sequence").
            vhQuery:query-open().
            do while true:
                vhQuery:get-next().
                if vhQuery:query-off-end then leave.
                ihResultSetBuffer:buffer-create().
                ihResultSetBuffer:raw-transfer(false,vhCacheDataTableBuffer).
                ihResultSetBuffer:buffer-release().
            end.
            vhQuery:query-close().
            delete object vhQuery.
            delete object vhCacheDataDataset.
            
            if (ilForwardRead = yes and viTo <= tQueryCache.RecordCount)
            or (ilForwardRead = no  and viFrom > 0)
            then olEndOfQuery = no.
        end.    /* vlgetdata = no */
        
    end.    /* ilCountOnly = no */
    
    /* Return this unique key back to the client in tFcMessages
      (because it cannot be added as a parameter to the generic API query interface)
    */
    <M-91 run SetMessage
       (input  'QueryCacheKey' (icMessage), 
        input  '' (icArguments), 
        input  'QueryCacheKey' (icFieldName), 
        input  vcSearchKey (icFieldValue), 
        input  'I' (icType), 
        input  0 (iiSeverity), 
        input  '' (icRowid), 
        input  'blf-251439':U (icFcMsgNumber), 
        input  '' (icFcExplanation), 
        input  '' (icFcIdentification), 
        input  '' (icFcContext), 
        output viFcReturnSuper (oiReturnStatus)) in BQueryCache>
end.

finally:
    delete object vhQueryDataset no-error.
end finally.