Try OpenEdge Now
skip to main content
ABL Reference
ABL Syntax Reference : DEFINE BUFFER statement
 

DEFINE BUFFER statement

ABL provides you with one default buffer for each table or temp-table that you use in a procedure or class. ABL uses that buffer to store one record at a time from the table as the records are needed during the procedure or class. If you need more than one record or buffer at a time for a table, you can use this statement to define alternate buffers that are created at compile time for use in one or more procedures, or within a single class or class hierarchy.

Syntax

DEFINE {[[ NEW ] SHARED ] | [ PRIVATE | PROTECTED ] [ STATIC ]}
  BUFFER buffer-name
  FOR [ TEMP-TABLE ]table-name
  [ PRESELECT ][ LABEL label-name]
  [ NAMESPACE-URI namespace][ NAMESPACE-PREFIX prefix]
  [ XML-NODE-NAME node-name]
NEW SHARED BUFFER buffer-name
Defines and identifies a buffer that can be used by other procedures. When the procedure using this statement ends, the buffer is no longer available.
SHARED BUFFER buffer-name
Defines and identifies a buffer that was created in another procedure with the DEFINE NEW SHARED BUFFER statement.
[ PRIVATE | PROTECTED ] [ STATIC ] BUFFER buffer-name
Defines and identifies a buffer as a data member of a class, and optionally specifies an access mode (PRIVATE or PROTECTED) and scope (instance or STATIC) for that data member. You cannot specify these options when defining a buffer as a data element of a method (including constructors, destructors, and property accessors) or a procedure.
Note: The specified options are applicable only when defining a data member for a class in a class definition (.cls) file. The PRIVATE/PROTECTED modifier and the STATIC modifier can appear in either order, e.g., DEFINE STATIC PRIVATE BUFFER myBuffer... is valid syntax. Note also that you cannot shadow (override) the definition of a given buffer data member in a class hierarchy.
PRIVATE buffer data members can be accessed by the defining class. An instance can access the private buffer data members of another instance if both instances are of the same class. PROTECTED buffer data members can be accessed by the defining class and any of its derived classes. An instance can access protected buffer data members of a second instance that is at the same level or higher in the class hierarchy. The default access mode is PRIVATE. When you reference a buffer from another data member definition (such as a query) defined in the same class or class hierarchy, the access mode of the buffer cannot be more restrictive than the access mode of the referencing data member.
A buffer defined with the STATIC option is a static data member of the class type for which it is defined and is scoped to the ABL session where it is referenced. ABL creates one copy of the specified class static buffer on first reference to the class type, and ABL creates only one such copy for any number of instances of the class that you create. You can directly reference an accessible static buffer data member from any other static or instance class member defined in the same class or class hierarchy.
Without the STATIC option, ABL creates an instance buffer data member that is scoped to a single instance of the class where it is defined. ABL creates one copy of the specified instance buffer for each such class instance that you create. You cannot directly reference an instance buffer data member from a STATIC class member definition defined within the same class or class hierarchy.
Within a class, ABL defines the default buffer for any database table as a PRIVATE instance buffer. Thus, for example, you can only access the default buffer for the Customer table of the sports2000 database wherever a PRIVATE instance buffer can be accessed. Otherwise, you must define an alternate buffer data member for the table with an appropriate access mode and scope.
For more information on accessing buffers of different access modes and scopes, see the reference entry for Class-based data member access.
Note: Members of a class are grouped into six namespaces, including buffers/temp-tables, methods, variables/properties/events, ProDataSets, queries, and data-sources. Buffers and temp-tables defined as members of a class share the same namespace. There can be only one class member in this namespace with a given name.
For more information on where and how to define data members in a class, see the CLASS statement reference entry.
BUFFER buffer-name
Defines and identifies a buffer whose records you can access only within the current procedure, method of a class (including constructors, destructors, and property accessors), or as a PRIVATE data member of a class.
FOR [ TEMP-TABLE ]table-name
Identifies the name of the table for which you are defining an additional buffer. This can also be the built-in buffer name, proc-text-buffer, to define a buffer that returns table rows from a stored procedure.
To define a buffer for a table defined for multiple databases, you might have to qualify the table name with the database name. See the Record phrase reference entry for more information.
Use the TEMP-TABLE option to define a buffer for a temp-table when the temp-table has the same name as a database table. Otherwise, ABL associates the buffer with the database table by default.
If you define the buffer as static, and table-name is the name of a temp-table, the temp-table must also be defined as a static member of a class.
PRESELECT
If you use the PRESELECT option with a DO or REPEAT block, the AVM creates an internal list of the records selected. The PRESELECT option tells the AVM to apply that internal list to the buffer you define. You can also use the PRESELECT option in the DEFINE SHARED BUFFER statement.
LABEL label-name
Specifies a label for the buffer. This label is used in error messages in place of the buffer name.
NAMESPACE-URI namespace
An optional CHARACTER constant that specifies the URI for the namespace of the buffer object.
NAMESPACE-PREFIX prefix
An optional CHARACTER constant that specifies the namespace prefix associated with the NAMESPACE-URI.
XML-NODE-NAME node-name
An optional CHARACTER constant that specifies the name of the XML element representing the temp-table buffer in an XML Document. The default is buffer-name.

Examples

This procedure allows the user to create a new Customer record. Initially, the City, State, and Country fields are not shown. After the user enters a PostalCode value, the procedure searches for an existing Customer with the same postal code. If such a Customer is found, the City, State, and Country values from that record are displayed in the fields for the new record. The user can then update those fields.
r-defb.p
DEFINE BUFFER other-cust FOR Customer.

FORM Customer WITH FRAME cre-cust.

ON LEAVE OF Customer.PostalCode DO:
  FIND FIRST other-cust
    WHERE other-cust.PostalCode = Customer.PostalCode:SCREEN-VALUE
    AND other-cust.CustNum <> Customer.CustNum NO-ERROR.
  IF AVAILABLE other-cust THEN
    DISPLAY other-cust.City @ Customer.City
      other-cust.State @ Customer.State
      other-cust.Country @ Customer.Country
      WITH FRAME cre-cust.
  ENABLE Customer.City Customer.State Customer.Country WITH FRAME cre-cust.
END.

CREATE Customer.
UPDATE Customer EXCEPT Customer.City Customer.State Customer.Country
   WITH FRAME cre-cust.
The following gather a group of records so that the user can enter any table name and any set of record selection criteria and then look at the records in the table that meet those criteria:
r-defb2.p
DEFINE VARIABLE fname      AS CHARACTER NO-UNDO
  FORMAT "x(12)" LABEL "Table name".
DEFINE VARIABLE conditions AS CHARACTER NO-UNDO
  FORMAT "x(60)" LABEL "Conditions".

REPEAT:
 /* Get the name of a table and, optionally, some record selection criteria */
 UPDATE fname COLON 12 conditions COLON 12
   WITH SIDE-LABELS 1 DOWN.
 HIDE ALL.
 IF conditions <> "" THEN
   /* Pass the table name and the record selection criteria as parameters */
   RUN r-defb3.p fname "WHERE" conditions.
 ELSE
   RUN r-defb3.p fname.
END.
The r-defb2.p procedure gets the name of a table (such as Customer) and a condition (such as CreditLimit > 4000) and passes them as arguments to the r-defb3.p procedure:
r-defb3.p
DEFINE NEW SHARED BUFFER rec FOR {1} PRESELECT.

DEFINE VARIABLE flist AS CHARACTER NO-UNDO EXTENT 12.
DEFINE VARIABLE ix    AS INTEGER   NO-UNDO.

/* Look in _File for the table named in the fname variable */
FIND _File "{1}".

/* Store the table's field names in the first array */
FOR EACH _Field OF _File USE-INDEX _Field-Posit:
  IF i >= 12 THEN LEAVE.
  i = i + 1.
  flist[i] = _Field._Field-Name.
END.

/* Preselect records */
DO PRESELECT EACH rec {2} {3} {4} {5} {6} {7} {8} {9} {10} {11} {12}:
  /* Pass the filenames and all field names to r-defb4.p */
  RUN r-defb4.p "{1}" flist[1] flist[2] flist[3] flist[4] flist[5] flist[6]
    flist[7] flist[8] flist[9] flist[10] flist[11] flist[12].
END.
The r-defb3.p procedure:
*Lets you view the OpenEdge Data Dictionary. The _File table contains a record for each of your database tables.
*Lets you look up a record for a Customer table. For example, the user supplies Customer as a table name; the FIND statement in the r-defb3.p procedure translates to FIND _File Customer. The FIND statement finds, in _File, the record for the Customer table.
*Lets you view the _Field table in the OpenEdge Data Dictionary. The _Field table contains a single record for each of your database fields. The FOR EACH statement reads the name of each of those fields into the first array variable. If the table name is Customer, the first array variable contains the names of each of the fields in the Customer table.
*Lets you select records. For example, the user supplies the condition CreditLimit > 4000 in the table name. The DO PRESELECT EACH rec statement translates to DO PRESELECT EACH rec WHERE MaxCredit > 4000. The AVM goes through the Customer table and selects the records that meet the criteria. It creates a temp-table containing a pointer to each of those records. This list of preselected records is associated with the rec buffer.
*Runs r-defb4.p, passing the table name (Customer) and the names of all of the fields in that table.
The r-defb4.p procedure has access to the rec buffer (and through it to the set of preselected records). This connection is made by using PRESELECT on the DEFINE SHARED BUFFER statement. The r-defb4.p procedure displays those records.
r-defb4.p
DEFINE SHARED BUFFER rec FOR {1} PRESELECT.

REPEAT:
  FIND NEXT rec.
  DISPLAY {2} {3} {4} {5} {6} {7} {8} {9} {10} {11} {12} {13}
    WITH 1 COLUMN 1 DOWN.
END.
Because r-defb3.p and r-defb4.p use run-time argument passing, they cannot be precompiled. Having separate versions of r-defb4.p for each table and running the appropriate one in r-defb3.p, should improve response time. This approach is worthwhile if there are many lines of code in r-defb4.p a procedure.
If you define a NEW SHARED BUFFER in a procedure, then call a subprocedure that puts a record into that buffer, and display the buffer in the main procedure, the AVM displays this message:
Missing FOR, FIND or CREATE for Customer.
This message is displayed when the FIND statement is not in the main procedure:
/* Main procedure */

DEFINE NEW SHARED BUFFER x FOR Customer.

RUN proc2.p.
DISPLAY x.
/* proc2.p */

DEFINE SHARED BUFFER x FOR Customer.

FIND FIRST x.
To avoid this, explicitly scope the Customer record to the main procedure block. For example:
/* Main procedure */

DEFINE NEW SHARED BUFFER x FOR Customer.


RUN proc2.p.
DO FOR x:
  DISPLAY x.
END.
For examples of instance and static buffer data member definitions, see the descriptions of r-CustObj.cls, r-CustObjStatic.cls, and r-CustObjAbstract.cls in the CLASS statement reference entry.

Notes

*You cannot define a SHARED or NEW SHARED buffer in a class definition (.cls) file. If you do, ABL generates a compilation error.
*A buffer can be compile-time defined (often referred to as a static buffer object), where the buffer is defined and created at compile time using this statement, or it can be run-time defined (often referred to as a dynamic buffer object), where the buffer is defined and created at run time using the CREATE BUFFER statement and buffer object handle operations. A compile-time defined buffer can also be defined as a static data member of a class. In this case, it is a static buffer object that is also a class static data member.
*Every statement that uses a table name to refer to the default buffer can also use the name of a defined alternate buffer.
*All data definitions and field names are associated with a table, not a buffer. Data definitions and field names remain the same no matter what buffer you use.
*If two buffers contain the same record, a change to one of the buffers is automatically reflected in the other buffer.
*You can pass a buffer as a parameter to a procedure.
*A SHARED buffer remains in scope for an instance of a persistent procedure until the instance is deleted. This is true even if the original procedure that defined the buffer as NEW SHARED goes out of scope while the procedure instance remains persistent.
If a trigger or internal procedure of a persistent procedure executes an external subprocedure that defines a SHARED buffer, ABL includes the persistent procedure in the resolution of the corresponding NEW SHARED buffer as though the procedure were on the procedure call stack.
*If you define a temp-table with the same name as a database table and you then define a buffer for that table name, by default the buffer will be associated with the database table, not with the temp-table. Use the TEMP-TABLE option to define a buffer for a temp-table when the temp-table has the same name as a database table.
*For more information on using the built-in buffer name proc-text-buffer, see the OpenEdge DataServer Guides (OpenEdge Data Management: DataServer for Microsoft SQL Server and OpenEdge Data Management: DataServer for Oracle).

See also

Class-based data member access, CREATE BUFFER statement, DEFINE PARAMETER statement, RUN statement, RUN STORED-PROCEDURE statement