3 Understanding Flists

Learn about flists (field lists), which pass data between Oracle Communications Billing and Revenue Management (BRM) processes.

Topics in this document:

About Flists

The flist is the primary data structure used in BRM. Flists are containers that hold fields, each consisting of a data field name and value. Flists do not contain actual data but instead provide links to the data's location. The only exceptions are integers and strings, which are stored in flists.

Here is a simple flist example:

0 PIN_FLD_LAST_NAME     STR [0] "Smith"
0 PIN_FLD_FIRST_NAME    STR [0] "Joe"
0 PIN_FLD_COMPANY       STR [0] "XYZ Corporation"
0 PIN_FLD_CURRENCY      INT [0] 840

Many BRM processes interpret data in flist format. For example, the storage manager in the Data Manager (DM) translates flists to a format that the database can process and then translates the data from the database into an flist before passing it to the Connection Manager (CM).

BRM uses flists in these ways:

  • Objects are passed as flists between opcodes or programs that manipulate the objects.

  • Opcodes use flists to pass data between BRM applications and the database. For each opcode, an input flist is passed to PCM_OP, and the return flist is passed back from this routine.

In an flist, you can use any data type such as decimals, buffers, arrays, and substructures. Flists can contain any number of fields. You can place flists within other flists. Remember, though, that except for integers, data is not stored in the flist; it just links to where the data is located.

For a description of the BRM data types you can use in an flist, see "Understanding the BRM Data Types".

Note:

[0] after the field type represents the element ID. The numbers 0, 1, 2, and so on at the beginning of each line indicate the field's nesting level, and 0 indicates the top level.

When you include a field in an flist, you must also include an abbreviation of the field's data type. Table 3-1 lists the valid BRM field types and their abbreviations.

Table 3-1 Flist Field Types

Field Type Abbreviation

PIN_FLDT_ARRAY

ARRAY

PIN_FLDT_BINSTR

BINSTR

PIN_FLDT_BUF

BUF

PIN_FLDT_DECIMAL

DECIMAL

PIN_FLDT_ENUM

ENUM

PIN_FLDT_ERRBUF

ERR

PIN_FLDT_INT

INT

PIN_FLDT_POID

POID

PIN_FLDT_STR

STR

PIN_FLDT_SUBSTRUCT

SUBSTRUCT

PIN_FLDT_TSTAMP

TSTAMP

Opcode Input and Output Specifications

Each PCM opcode requires specific data to perform its operation. The opcodes take input and output data as field lists (flists), which are lists of field name and value pairs. For more information about flists, see "About Flists".

Each opcode requires its input flist to contain specific fields for operation. For example, to create an object, the PCM_OP_CREATE_OBJECT() opcode requires an input flist that includes all the fields that an object of that storable class requires.

The Opcode Flist Reference contains the input and output flist specifications for each opcode, defining the following parameters for each field in the flist:

  • The mnemonic field names used by applications to reference the field

  • The data type and size for the field

  • The permissions, which specify if a field is mandatory (M) or optional (O)

The flist specifications use the following syntax to define each field in an flist:

class depth field (
   type = data_type
   perms = permission permission ...,
);

where:

  • class specifies whether it is a field, array, or a substruct.

  • depth contains an asterisk for each nesting level of the field.

  • field specifies the name of the field.

Examples:

field PIN_FLD_NAME (
      type    =    PIN_FLDT_STR(255),
      perms   =    M,
);
array * PIN_FLD_INHERITED_INFO (
        type    =               PIN_FLDT_ARRAY,
        perms   =               O,
);

The flist specifications specify whether a field is mandatory or optional.

About Creating and Using an Flist

You create and manipulate flists with the flist manipulation macros in the Portal Information Network (PIN) library. You can add, remove, and modify fields using the flist field-handling macros. For more information, see "Flist Management Macros" and "Flist Field-Handling Macros" in BRM Developer's Reference.

Each opcode has an input and output flist specification. Create an flist for each opcode you call for the data you want to pass in. When you create an input or an output flist for an opcode, follow the flist specifications. See the flist specifications in the individual opcode descriptions.

Flists are dynamically allocated data structures. When a field is added to an flist, the value is either already dynamically allocated in memory or copied into dynamic memory as it is added.

Note:

Destroy the flist you create in your programs to reclaim the memory that the flist occupies. For details, see "Destroying Flists".

Adding Information to Flists

You add data to flists by replacing pointers to data using these flist management macros:

  • PIN_FLIST_ELEM_PUT

  • PIN_FLIST_FLD_PUT

  • PIN_FLIST_SUBSTR_PUT

Note:

(Release 15.0.1 or later) You can pass a compilation switch from your custom source code's build scripts, which causes pointers to objects that are PUT to flists to be set to NULL, preventing them from accidentally being destroyed (causing a double-free error) in later code.

For details on these macros, see "Flist Management Macros" in BRM Developer's Reference.

You add data to flists by replacing the data itself using these flist management macros:

  • PIN_FLIST_ELEM_SET

  • PIN_FLIST_FLD_SET

  • PIN_FLIST_SUBSTR_SET

For details on these macros, see "Flist Management Macros" in BRM Developer's Reference.

Removing Data (Pointers) from an Flist

You remove a pointer to data from an flist and add it to another flist by using these flist management macros:

  • PIN_FLIST_ELEM_TAKE

  • PIN_FLIST_FLD_TAKE

  • PIN_FLIST_SUBSTR_TAKE

Note:

These macros overwrite existing pointers to data, not the data itself. To free the memory used by the old data, destroy the memory location using PIN_FLIST_DESTROY_EX. Otherwise, a memory leak may occur.

You usually use the TAKE macros when you want to take data from an flist and change it.

Note:

When you use a TAKE macro to remove a pointer to data, you must free the memory when finished. If the memory is not freed, memory leaks may occur.

For details on these macros, see "Flist Management Macros" in BRM Developer's Reference.

Copying Data from an Flist

You copy a pointer to data from one flist to another by using these flist management macros:

  • PIN_FLIST_ELEM_GET

  • PIN_FLIST_FLD_GET

  • PIN_FLIST_SUBSTR_GET

You usually use the GET macros when you want to copy data but not change it.

Note:

You should treat any data that you GET using these macros as read-only because the original program may also need it.

For details on these macros, see "Flist Management Macros" in BRM Developer's Reference.

Destroying Flists

You destroy an flist and free its memory by using these flist management macros in BRM Developer's Reference:

Flists use dynamically allocated memory and must be destroyed to free that memory and prevent memory leaks. These macros first determine whether the flist has a NULL value. If so, they do nothing. If the flist exists, these macros destroy its entire contents, including all fields.

PIN_FLIST_DESTROY_EX sets the reference to the flist to a NULL value after it destroys the flist.

PIN_FLIST_DESTROY frees the memory for the flist field-value pairs, but does not set a reference to that flist to NULL. If another program subsequently attempts to destroy this flist (with freed memory but a valid flist pointer), unexpected behavior and core dumps can result.

For details on these macros, see "Flist Management Macros" in BRM Developer's Reference.

Flist Creation Samples

BRM SDK includes flist creation samples in C, C++, Java, and Perl. Three samples are provided for each language: one to create a simple flist, another to create an flist with a nested array, and a third to create an flist with a substructure. For information about installing and using BRM SDK, see "About BRM SDK".

You can view the following sample programs in BRM Developer's Reference:

These documents also include information about compiling and running the programs.

Using Compile-Time Flags to Avoid Errors in Flists (Release 15.0.1 or later)

The PUT family of flist macros effectively transfers ownership of an object to the target flist. The object could be a decimal object, another flist, a POID, or so on. During this process, the source pointer may no longer contain a reliable reference to the original object that was PUT. For example, the target flist may subsequently be destroyed so that the pointer now refers to an area of memory that has been freed and contains garbage. Using that pointer after the PUT may result in a crash or other undefined behavior. This is a common source of defects in programs, which can be resolved by the following idiomatic coding style:

PIN_FLIST_ELEM_PUT(target_flistp, source_elemp, PIN_FLD_PRODUCTS, elemid, ebufp);
source_elemp = NULL;

This idiom helps avoid cases where source_elemp is used after the PUT where it may no longer be a valid pointer.

To reduce program errors and the burden on programmers to remember to set the source pointer variable to NULL, you can configure the BRM flist API to update the source pointer to NULL directly. This avoids errors where programmers forget to reset a pointer to NULL and simplifies the code, reducing verbosity.

To permit BRM to automatically set the source pointer to NULL during PUT operations in custom application code, set the compile-time flags in Table 3-2 in your custom code's Makefile.

Table 3-2 Compile-Time Flags for Each Flist Macro

Flist Macro Compile-Time Flag

PIN_FLIST_SUBSTR_PUT

-DASSIGN_NULL_AFTER_SUBSTR_PUT

PIN_FLIST_ELEM_PUT

-DASSIGN_NULL_AFTER_ELEM_PUT

PIN_FLIST_FLD_PUT

-DASSIGN_NULL_AFTER_FLD_PUT

Note:

After enabling this feature, existing code may crash if it unsafely uses the original object pointer. However, this is not a cause for alarm. It simply means that the feature has exposed a potential code defect. To fix this, you can modify the code to remove the unsafe access, such as by deferring the PUT until later or reorganizing the logic to be safe with appropriate checks for a NULL pointer.

The following shows a sample error you could encounter after enabling one of the compile-time flags in your new or existing custom code and attempting to compile:

In file included from fm_ar_event_utils.c:31:0:
fm_ar_event_utils.c: In function 'fm_bill_adjust_event_find_adjustments':
/scratch/temp/portalbase/publish_linux_vob/publish_linux/include/pcm.h:2211:42: error: value required as left operand of assignment
 #define SET_NULL_TO_FLD_VALUE(valp) valp = NULL;
/scratch/temp/portalbase/publish_linux_vob/publish_linux/include/pcm.h:2228:9: note: in expansion of macro 'SET_NULL_TO_FLD_VALUE'
         SET_NULL_TO_FLD_VALUE(valp);                                    
fm_ar_event_utils.c:1400:4: note: in expansion of macro 'PIN_FLIST_FLD_PUT'
    PIN_FLIST_FLD_PUT(read_flistp, PIN_FLD_POID, (void *)rerate_obj, ebufp);

Table 3-3 shows how to fix possible compilation error types in sample code using the PIN_FLIST_FLD_PUT macro.

Table 3-3 Fixing Sample Code with Compile Errors

Compilation Error Type Problematic Code Fixed Code

Type casting

PIN_FLIST_FLD_PUT(srch_args_flistp, 
PIN_FLD_POID, (void *)s_pdp, ebufp);
PIN_FLIST_FLD_PUT(srch_args_flistp, 
PIN_FLD_POID, s_pdp, ebufp);

Putting an object that results from a function call

PIN_FLIST_FLD_PUT(flistp, PIN_FLD_PERCENT, 
(void *)pbo_decimal_round(pct, precision, ROUND_HALF_UP, ebufp);
pin_decimal_t *tmp_rounded_val = 
pbo_decimal_round(pct, precision, ROUND_HALF_UP, ebufp);
PIN_FLIST_FLD_PUT(flistp, PIN_FLD_PERCENT, tmp_rounded_val, ebufp);

Putting stack-allocated memory on an flist

char str_msg[50];
PIN_FLIST_FLD_PUT(out_flistp, PIN_FLD_NAME, str_msg, ebufp);
PIN_FLIST_FLD_SET(out_flistp, PIN_FLD_NAME, str_msg, ebufp);

Note: Use PIN_FLST_FLD_SET to copy the string onto the flist as heap-allocated memory since str_msg is allocated on the stack, not the heap, and therefore becomes invalid when exiting the current lexical scope.

Putting NULL

PIN_FLIST_FLD_PUT(flistp, PIN_FLD_STATUS, NULL, ebufp);
PIN_FLIST_FLD_SET(flistp, PIN_FLD_STATUS, NULL, ebufp);

Note: Use PIN_FLIST_FLD_SET, since NULL is not dynamically allocated memory.

Flist Management Rules

Follow these rules when creating programs that manipulate flists:

  • The calling applications are responsible for allocating memory for input flists. This includes cases where you use a wrapper opcode to call another opcode.

  • The opcode being called is responsible for allocating memory for output flists. For more information, see "About Creating and Using an Flist".

  • The calling applications are responsible for destroying both input and output flists.

  • The opcode being called is responsible for destroying both input and output flists if the opcode utilizes a wrapper opcode to call another opcode. For more information, see "Destroying Flists".

  • You should never destroy an input flist within an opcode, because a calling application may need it.

  • These flist management macros in BRM Developer's Reference allocate new memory:

    You must explicitly free a newly created flist using the PIN_FLIST_DESTROY_EX macro unless that flist will be used for the opcode output.

Example

You use the following syntax to copy an flist:

*out_flistpp = PIN_FLIST_COPY(in_flistp, ebufp);

Flist Field Memory Management Guidelines

You use the following guidelines when creating your programs to avoid memory problems:

For details on these macros, see "Flist Management Macros" in BRM Developer's Reference.

Handling Errors

All flist routines take a pointer to pin_ebuf_t as the final argument. This pointer, called ebufp, must point to a preallocated pin_ebuf_t into which error information is written.

The BRM APIs use the pin_ebuf_t structure to pass back detailed information about the error. BRM includes standard logging routines that print formatted log messages using the date in pin_ebuf_t. You can use these log messages to determine where the error occurred.

See "Finding Errors in Your Code" for more information on how BRM handles error messages.