Salesforce

4GL. How to convert a ROWID to a RECID and Vice Versa

« Go Back

Information

 
Title4GL. How to convert a ROWID to a RECID and Vice Versa
URL Name21616
Article Number000136222
EnvironmentProduct: Progress
Version: 9.x
Product: OpenEdge
Version: All Supported Versions
OS: All Supported Platforms
Question/Problem Description
4GL. How to convert a ROWID to a RECID and Vice Versa
Sample methods to convert a ROWID variable to a RECID variable.
Sample methods to convert a RECID variable to a ROWID variable.
Steps to Reproduce
Clarifying Information
Error Message
Defect Number
Enhancement Number
Cause
Resolution
There is no native ABL function that converts ROWID variables to RECID variables or visa versa.  One must exercise caution when trying to convert a RECID to a ROWID, as the converted ROWID value may not always identify the current database record if it doesn't contain all of the information as the record's ROWID.
ROWIDs
  • A ROWID is a unique internal identifier of the current database record.  
  • A ROWID may be converted to a character string representation of the ROWID value using the STRING function.
  • A ROWID value converts to a hexadecimal string of the form "0xhexdigits," where hexdigits is any number of characters "0" through "9" and "A" through "F"
  • The TO-ROWID Function converts a string representation of a valid ROWID to a valid ROWID value.  Although TO-ROWID converts a properly formatted string to a ROWID value, there is no guarantee that this value corresponds to an existing record in your database.
RECIDs
  • A RECID  is a unique internal identifier of the current database record, which is supported mainly for backward compatibility.
  • For most applications, Progress recommends the use of ROWID to identify existing records in a table.  A RECID variable has a default INTEGER type representation and may be only part of the ROWID value.
  • With the implementation of the Table Partitioning feature in OpenEdge 11.4, RECID can no longer be used to uniquely reference data in a partitioned table as they do not contain a partition-Id component and always pertain to partition 0.
  • The existing RECID plus the table number is no longer sufficient to uniquely identify a specific record in the database.  
  • Uniqueness is obtained by also including the Partition Id associated with the record.  The internal format of a ROWID has been extended to include the partition information(4 digits at the end of the ROWID).  The information associated with a RECID only contains the encoded block and record within block information. For further information refer to Article: 

In the below code, the HexToInt function converts a ROWID to a RECID, and also returns the Partition Id of the record.  If 0 is returned for the Partition Id, this indicates that the record is not in a partitioned table.

The IntToHex function converts a RECID and a Partition Id (if available) to a ROWID.  If 0 is passed to the Partition Id field, it is assumed the record is not in a partitioned table.
NOTE: When working with 32Bit RECIDs, change the below INT64 variables, parameters and return types to INTEGER.
FUNCTION HexToInt RETURNS INT64
    ( INPUT  pcRowid     AS CHARACTER,
      OUTPUT piPartition AS INTEGER ):
    DEFINE VARIABLE iRecid AS INT64   NO-UNDO INITIAL 0.
    DEFINE VARIABLE iChar  AS INTEGER NO-UNDO.

    DEFINE VARIABLE iCode AS INTEGER     NO-UNDO.
    DEFINE VARIABLE iExp  AS INT64       NO-UNDO.

    /* Strip the leading 0x from the ROWID value */    
    IF pcRowid BEGINS "0x" THEN
        pcRowid = SUBSTRING(pcRowid,3).

    IF LENGTH(pcRowid) GT 16 THEN
        ASSIGN piPartition = INTEGER(SUBSTRING(pcRowid,17))
               pcRowid     = SUBSTRING(pcRowid,1,16).
    ELSE piPartition = ?.

    pcRowid = CAPS(pcRowid).
    DO iChar = 1 TO LENGTH(pcRowid):
        IF CAN-DO("0,1,2,3,4,5,6,7,8,9", 
                  (SUBSTRING(pcRowid, iChar, 1))) THEN
            ASSIGN iRecid = iRecid + INTEGER(SUBSTRING(pcRowid, iChar, 1)) *
                     EXP(16, (LENGTH(pcRowid) - iChar)).
        ELSE
            ASSIGN iRecid = iRecid + (KEYCODE(SUBSTRING(pcRowid,iChar,1)) -
                            KEYCODE("A") + 10) * INT64(EXP(16, LENGTH(pcRowid) - iChar)).
    END.

    RETURN iRecid.
END FUNCTION.

FUNCTION IntToHex RETURNS CHARACTER
    ( /* RECID to ROWID conversion */
      INPUT piRecid  AS INT64,
      INPUT piPartId AS INTEGER ):

    DEFINE VARIABLE cRowid     AS CHARACTER   NO-UNDO.
    DEFINE VARIABLE iRemainder AS INTEGER     NO-UNDO.
    DEFINE VARIABLE iAsc       AS INTEGER     NO-UNDO.

    ASSIGN /*piPartId = (if piPartId EQ ? THEN 0 ELSE piPartId)*/
           iAsc     = ASC("a").     

    DO WHILE TRUE:        
        ASSIGN iRemainder = (piRecid MOD 16)
               cRowid = (IF iRemainder LT 10 THEN
                             STRING(iRemainder)
                         ELSE
                             CHR(iAsc + iRemainder - 10)) +
                        cRowid.

        IF piRecid LT 16 THEN
            LEAVE.
 
        piRecid = (piRecid - iRemainder) / 16.
    END.

    iRemainder = (16 - LENGTH(cRowid)).
    DO piRecid = 1 TO iRemainder:
        cRowid = "0" + cRowid.
    END.

    cRowid = "0x" + cRowid.
    IF piPartId NE ? AND
       piPartId GE 0 THEN
        cRowid = cRowid + STRING(piPartId,"9999").
    
    RETURN cRowid.
END FUNCTION.

DEFINE VARIABLE iRecId       AS INT64     NO-UNDO.
DEFINE VARIABLE cRowId       AS CHARACTER NO-UNDO.
DEFINE VARIABLE rRowID       AS ROWID     NO-UNDO.
DEFINE VARIABLE iPartitionId AS INTEGER   NO-UNDO.

FIND FIRST Customer NO-ERROR.
cRowId = STRING(ROWID(Customer)).

iRecId = HexToInt(INPUT cRowId, OUTPUT iPartitionId).

/* This may not be successful if the table is partitioned because it's 
   not using the Partition Id.   */
FIND Customer WHERE RECID(Customer) = iRecId NO-ERROR.

MESSAGE NAME iRecId SKIP
        "Do the ROWIDs match from HexToInt function? " 
        (IF NOT AVAILABLE Customer THEN FALSE
         ELSE cRowid EQ STRING(ROWID(Customer)))
   VIEW-AS ALERT-BOX INFO BUTTONS OK.

cRowid = IntToHex(iRecid,iPartitionId).
FIND Customer WHERE ROWID(Customer) EQ TO-ROWID(cRowid) NO-ERROR.
MESSAGE "Do the RECIDs match from the IntToHex function? "
        (IF NOT AVAILABLE Customer THEN FALSE
         ELSE iRecid EQ INT64(RECID(Customer)))
    VIEW-AS ALERT-BOX INFORMATION BUTTONS OK.
    
Note: 000001594.zip includes example code modifying the above code for running on 32-bit or 64-bit systems.
Workaround
Notes
References to other Documentation:

Progress article(s):
 4GL. How To Retrieve Records by ROWID in a Dynamic-Query

Note: 000001594.zip has been added to the knowledgebase article. This zip file contains three
files as follows: torecid.p, rowid_recid.p and readmefirst.txt. rowid_recid.p is the first block of code included earlier in the article but updated to run on 32-bit or 64-bit OpenEdge (the existing code assumes integer datatype only). torecid.p was submitted by a member of the community for converting rowid to recid on 64-bit OpenEdge only.  readmefirst.txt explains the two executable files.
Keyword Phrase
Last Modified Date12/20/2023 11:46 AM

Powered by