Salesforce

4GL/ABL: How to check whether a given record exists, locked by another user or does not exist?

« Go Back

Information

 
Title4GL/ABL: How to check whether a given record exists, locked by another user or does not exist?
URL NameP122034
Article Number000144796
EnvironmentProduct: Progress / OpenEdge
Version: 9.x / 10.x, 11.x
OS: All supported platforms
Question/Problem Description
4GL/ABL: How to check whether a given record exists, locked by another user or does not exist?
How to include a database name in a dynamic query.
How to conditionally define variables using the &IF preprocessor directive.
How to dynamically determine a record's existence and locking status when multiple databases are connected.
Steps to Reproduce
Clarifying Information
Error Message
Defect Number
Enhancement Number
Cause
Resolution

The following procedure recordCheck.p checks whether a specific record exists or does not exist at all. If exists checks whether a record is locked by another customer or not. In all three cases the pop-up message is displayed. For screenshots please refer to attached zip file.

To demonstrate all three situations follow the steps:
-> connect to sports DB
TEST 1: Record exists and is not locked
             -> run the procedure recordCheck.p 
             -> message "The specified record EXISTS & NOT locked" is displayed (see the screenshot)

TEST 2: Record exists and is locked
             -> run the procedure recordLock.p
             -> run the procedure recordCheck.p 
             -> message "The specified record is LOCKED" with other useful information is displayed (see the screenshot)

TEST 3: Record does not exist
             -> set variable in PROCEDURE GetRecordRecid as follows: cWhereString   = 'cust-num = 20000'
             -> run the procedure recordCheck.p
             -> message "The specified record does NOT exist" is displayed (see the screenshot)

Procedure recordLock.p

FIND customer WHERE cust-num = 15 EXCLUSIVE-LOCK.
DISPLAY customer WITH 1 COLUMN.
UPDATE customer.NAME.

Procedure recordCheck.p

DEFINE VARIABLE cDatabaseName  AS CHARACTER NO-UNDO.
DEFINE VARIABLE cTableName     AS CHARACTER NO-UNDO.
DEFINE VARIABLE cBufferTable   AS CHARACTER NO-UNDO.
DEFINE VARIABLE cWhereString   AS CHARACTER NO-UNDO.
DEFINE VARIABLE cPrepareString AS CHARACTER NO-UNDO.
DEFINE VARIABLE cRecordStatus  AS CHARACTER NO-UNDO.

DEFINE VARIABLE hBufferHandle  AS HANDLE    NO-UNDO.
DEFINE VARIABLE hFieldHandle   AS HANDLE    NO-UNDO.
DEFINE VARIABLE hQueryHandle   AS HANDLE    NO-UNDO.

DEFINE VARIABLE iTableNumber   AS INTEGER   NO-UNDO.
DEFINE VARIABLE iRecordRecid   AS INTEGER   NO-UNDO.
DEFINE VARIABLE i_Lock-Table   AS INTEGER   NO-UNDO.


/* Starting with 10.1B, the INT64 data type is used for some _lock table fields */
/* Modify the &IF statement conditions to use it under version 8.x and earlier. */

&IF (PROVERSION BEGINS "9") OR (PROVERSION BEGINS "10.0") OR (PROVERSION BEGINS "10.1A") &THEN
    DEFINE VARIABLE i_Lock-Id    AS INTEGER       NO-UNDO.
    DEFINE VARIABLE i_Lock-RecId AS INTEGER       NO-UNDO.
&ELSE
    DEFINE VARIABLE i_Lock-Id    AS INT64       NO-UNDO.
    DEFINE VARIABLE i_Lock-RecId AS INT64       NO-UNDO.
&ENDIF                                                                

/* Get user table number */
RUN getTableNumber.

/* Get the user table record RECID */
RUN GetRecordRecid.

/* If the record does not exist then stop */
IF iRecordRecid = ? OR iRecordRecid = 0 THEN
    ASSIGN
        cRecordStatus = "The specified record does NOT exist".
ELSE
    /*  The record DOES exist, check its locking status */
    RUN CheckRecordLockStatus.

/* Finally, message the findings and destroy last dynamic query */
MESSAGE cRecordStatus
    VIEW-AS ALERT-BOX INFO BUTTONS OK.

RUN DestroyQuery.

/*============= PROCEDURE GetTableNumber ===============*/
PROCEDURE GetTableNumber:
    ASSIGN
        cDatabaseName  = "sports"      /*change if required*/
        cTableName     = "Customer"    /*change if required*/
        cBufferTable   = cDatabaseName + "." + "_File"
        cWhereString   = cBufferTable + '._File-Name = ' + QUOTER(cTableName)
        cPrepareString = 'FOR EACH ' + cBufferTable + ' NO-LOCK WHERE ' + cWhereString.

    RUN BuildQery.
  
    hQueryHandle:GET-FIRST(NO-LOCK).

    IF hBufferHandle:AVAILABLE  THEN DO:
        hFieldHandle = hBufferHandle:BUFFER-FIELD("_File-Number").
        iTableNumber = hFieldHandle:BUFFER-VALUE.
    END.

    RUN DestroyQuery.
END PROCEDURE.

/*============= PROCEDURE GetRecordRecid ===============*/
PROCEDURE GetRecordRecid:
    ASSIGN
        cBufferTable   = cDatabaseName + "." + cTableName
        cWhereString   = 'cust-num = 15'  /*change if required*/
        cPrepareString = 'FOR EACH ' + cBufferTable + ' NO-LOCK WHERE ' + cWhereString.

    RUN BuildQery.
   

    hQueryHandle:GET-FIRST(NO-LOCK).

    IF hBufferHandle:AVAILABLE THEN
        iRecordRecid = hBufferHandle:RECID.

    RUN DestroyQuery.
END PROCEDURE.

/*============= PROCEDURE CheckRecordLockStatus ========*/
PROCEDURE CheckRecordLockStatus:
    ASSIGN
        cBufferTable   = cDatabaseName + "." + "_Lock"
        cWhereString   = ""
        cPrepareString = 'FOR EACH ' + cBufferTable + ' FIELDS (_lock-Id _Lock-Table _Lock-Recid) NO-LOCK WHERE ' + cWhereString
        cRecordStatus =
        "The specified record EXISTS & NOT locked" + "~n" +
        "Record Recid:"    + "~t~t" +  STRING(iRecordRecid) + "~n" +
        "Record Table:"    + "~t~t" +  STRING(iTableNumber).

    RUN BuildQery.

    REPEAT:

        hQueryHandle:GET-NEXT(NO-LOCK).

        IF  ( hQueryHandle:QUERY-OFF-END ) OR ( NOT hBufferHandle:AVAILABLE ) THEN LEAVE.

        ASSIGN
            hFieldHandle = hBufferHandle:BUFFER-FIELD("_Lock-Table")
            i_Lock-Table = hFieldHandle:BUFFER-VALUE
            hFieldHandle = hBufferHandle:BUFFER-FIELD("_Lock-RecId")
            i_Lock-RecId = hFieldHandle:BUFFER-VALUE
            hFieldHandle = hBufferHandle:BUFFER-FIELD("_Lock-Id")
            i_Lock-Id    = hFieldHandle:BUFFER-VALUE.

        IF  ( i_Lock-Table = ? ) OR ( i_Lock-RecId = ? ) THEN LEAVE.

        IF  ( i_Lock-Table <> iTableNumber ) OR ( i_Lock-RecId <> iRecordRecid ) THEN NEXT.

        /*  If we reach here, the variable i_Lock-Id is our _Lock table _Lock-Id value */
        RUN DestroyQuery.

        RUN GetLockingDetails.
    END.
END PROCEDURE.

/*============= PROCEDURE GetLockingDetails ============*/ 
PROCEDURE GetLockingDetails:
    DEFINE VARIABLE iFieldCounter AS INTEGER NO-UNDO.

    ASSIGN
        cBufferTable   = cDatabaseName + "." + "_Lock"
        cWhereString   = "_Lock-Id = " + STRING(i_Lock-Id)
        cPrepareString = 'FOR EACH ' + cBufferTable + ' NO-LOCK WHERE ' + cWhereString.

    RUN BuildQery.

    hQueryHandle:GET-FIRST(NO-LOCK).

    IF hBufferHandle:AVAILABLE THEN DO:
        cRecordStatus = "The specified record is LOCKED. Details follow" + "~n".
        DO iFieldCounter = 1 TO hBufferHandle:NUM-FIELDS:
            hFieldHandle = hBufferHandle:BUFFER-FIELD(iFieldCounter).
            IF  hFieldHandle:BUFFER-VALUE <> ? THEN
                cRecordStatus = cRecordStatus + hFieldHandle:NAME + ":~t" + hFieldHandle:BUFFER-VALUE + "~n".
        END.
    END.
END PROCEDURE.

/*============= PROCEDURE BuildQery ====================*/
PROCEDURE BuildQery:
    CREATE BUFFER  hBufferHandle FOR TABLE cBufferTable.
    CREATE QUERY  hQueryHandle.

    hQueryHandle:SET-BUFFERS(hBufferHandle).
    hQueryHandle:QUERY-PREPARE(cPrepareString).
    hQueryHandle:QUERY-OPEN.
END PROCEDURE.

/*============= PROCEDURE DestroyQuery =================*/
PROCEDURE DestroyQuery:
    hQueryHandle:QUERY-CLOSE.

    DELETE OBJECT hBufferHandle.
    DELETE OBJECT hQueryHandle.

    ASSIGN
        hBufferHandle = ?
        hQueryHandle  = ?.
        hFieldHandle  = ?.
END PROCEDURE.

 

Workaround
Notes
Keyword Phrase
Last Modified Date11/20/2020 7:13 AM

Powered by