3 Understanding Flists and Storable Classes

This chapter provides an introduction to flists (field lists), which pass data between Oracle Communications Billing and Revenue Management (BRM) processes and storable objects that store data in the BRM database.

For instructions on creating storable classes, see "Creating Custom Fields and Storable Classes".

About Flists

The flist is a fundamental data structure used in BRM. Flists are containers that hold fields, each of which is a pair consisting of a data field name and its value. Flists do not contain actual data, but instead provide links to where the data is located. The one exception to this is integers, which are stored in flists.

Here is a simple flist example:

LAST_NAME       STR     "Smith"
FIRST_NAME      STR     "Joe"
COMPANY         STR     "XYZ Corporation"
  

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:

  • Storable objects are passed in the form of flists between opcodes or programs that manipulate the storable 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.

Contents of an Flist

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, 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". For a list of data type abbreviations used in flists, see "Flist Field Data Types".

The following example shows a partial input flist for the PCM_OP_CUST_COMMIT_CUSTOMER opcode:

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 nesting level of the field; 0 indicates the top level.
0 PIN_FLD_POID                  POID [0] 0.0.0.1 /plan 11950 0
0 PIN_FLD_CREATED_T            TSTAMP [0] (937336272) 09/14/99 12:11:12
0 PIN_FLD_MOD_T                TSTAMP [0] (937336272) 09/14/99 12:11:12
0 PIN_FLD_ACCOUNT_OBJ            POID [0] 0.0.0.1 /account -1 0
0 PIN_FLD_DEAL_OBJ               POID [0] 0.0.0.0  0 0
0 PIN_FLD_DESCR                   STR [0] "IP with 10 Free hrs per month"
0 PIN_FLD_NAME                    STR [0] "Basic"
0 PIN_FLD_LIMIT                 ARRAY [840] allocated 3, used 3
1     PIN_FLD_CREDIT_FLOOR        NUM [0] 0.000000
1     PIN_FLD_CREDIT_LIMIT        NUM [0] 100.000000
1     PIN_FLD_CREDIT_THRESHOLDS   INT [0] 0
0 PIN_FLD_SERVICES              ARRAY [0] allocated 4, used 4
1     PIN_FLD_DEAL_OBJ           POID [0] 0.0.0.1 /deal 9390 0
1     PIN_FLD_SERVICE_OBJ        POID [0] 0.0.0.1 /service/ip -1 0
1     PIN_FLD_LOGIN               STR [0] "aac4"
1     PIN_FLD_PASSWD_CLEAR        STR [0] "aac4"
0 PIN_FLD_NAMEINFO              ARRAY [1] allocated 10, used 10
1     PIN_FLD_CONTACT_TYPE        STR [0] "Billing"
1     PIN_FLD_LAST_NAME           STR [0] "aac1"
1     PIN_FLD_FIRST_NAME          STR [0] "aac1"
1     PIN_FLD_TITLE               STR [0] "aac1"
1     PIN_FLD_COMPANY             STR [0] "aac1"
1     PIN_FLD_ADDRESS             STR [0] "aac1"
1     PIN_FLD_CITY                STR [0] "aac1"
1     PIN_FLD_STATE               STR [0] "CA"
1     PIN_FLD_ZIP                 STR [0] "99999"
1     PIN_FLD_COUNTRY             STR [0] "USA"
0 PIN_FLD_BILLINFO              ARRAY [1] allocated 3, used 3
1     PIN_FLD_ACCESS_CODE1        STR [0] "aac1"
1     PIN_FLD_ACCESS_CODE2        STR [0] "aac1"
1     PIN_FLD_BILL_TYPE          ENUM [0] 10001
0 PIN_FLD_ACTGINFO              ARRAY [1] allocated 0, used 0
0 PIN_FLD_LOCALES               ARRAY [1] allocated 1, used 1
1     PIN_FLD_LOCALE              STR [0] "ENU"
.
.
.

Flist Field Data Types

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 abbreviation.

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


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 in an flist by 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. For each opcode you call, you must create an flist for the data you want to pass in. Follow the flist specifications for the opcode when you create an input or an output flist for an opcode. See the flist specifications in the individual opcode descriptions.

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

Important:

You must destroy the flist you create in your programs to reclaim the memory that the flist occupied. For details, see "About Destroying Flists".

About 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

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.

About 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

Important:

These macros overwrite existing pointers to data, not the data itself. To free the memory used by the old data, you must 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.

Important:

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.

About 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.

Important:

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

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.

About 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 the entire contents of the flist, 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 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 "About 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 de-allocate the memory allocated unless it is used for an output flist.

  • Memory allocation behavior depends on whether the opcode is called through a network (client/server) connection or within an internal Connection Manager (CM) process.

    • If the opcode is called through a client/server connection, the calling application and the CM do not share the same memory. An opcode with memory allocation issues may work if called by a Portal Communications Protocol (PCP) connection, but core dumps if called internally by another opcode.

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 "Understanding API Error Handling and Logging" for more information on how BRM handles error messages.

About Storable Classes and Storable Objects

Storable classes are used to store data in the BRM database. A storable class is a template consisting of a collection of fields in the BRM database. Storable objects are instances of storable classes.

Storable objects are stored persistently in SQL tables in the BRM database. To understand how storable objects are mapped to SQL tables, see "Storable Class-to-SQL Mapping" in BRM Developer's Reference.

Storable objects are passed in the form of flists between opcodes or programs that use the storable objects. For detailed information about flists, see "About Flists".

You manipulate the storable objects by using opcodes in the Portal Communication Module Application Programming Interface (PCM API). For more information about the PCM API, see "Understanding the PCM API and the PIN Library".

Each storable object has a unique Portal object ID (POID).

For a description of the BRM POIDs, see "Portal Object ID (POID)".

Class Naming and Formatting Conventions

BRM uses the following conventions for class names and definitions:

  • A class name begins with a forward slash (/). For example: /config.

  • Each slash in a class name represents a level of class inheritance. For example /config/adjustment is a subclass of /config and /config/adjustment/event is a subclass of /config/adjustment.

Class Inheritance

You can subclass a storable class to extend its functionality. When you subclass a storable class, the subclass inherits all the fields defined in the parent class and can have additional fields specific to the subclass. For example, the /service/email storable class contains all the information in the /service class plus additional information, such as login name and email address, specific to the email service.

Subclassing

Base classes are parent classes predefined in BRM from which you can create subclasses to add new functionality. Subclasses of storable classes can be extended or unextended:

  • An extended subclass inherits all the fields defined in its base class and contains new fields that add functionality specific to the subclass, as illustrated by the /service/email subclass.

    You can create a subclass of an extended subclass to add functionality to an extended subclass. An example of this type of subclass is /config/adjustment/event.

  • An unextended subclass inherits all the fields defined in its base class but does not contain any new fields for additional functionality. The only difference between an unextended subclass and its base class is the class type.

    The unextended subclasses are primarily used for tracking and for grouping subclasses with similar functionality. For example, /event/billing is a subclass of /event, but it does not contain any additional fields. It is primarily used to group different BRM billing events, such as charge, debit, and payment.

When you subclass a predefined base class or a subclass by adding new fields, your new class has the following characteristics:

  • The same fields as its original base class with the attributes of that class.

  • Any new fields you add.

  • The common defined behavior and functionality of storable classes in BRM.

About Defining Storable Classes

You use fields to define storable classes. Fields in storable classes have corresponding fields in opcode input flists. The fields in the objects receive specific instructions and behavior from the corresponding fields in the opcode that manipulates the object.

Each field has the following parts:

  • A mnemonic name that describes its function. For example, PIN_FLD_LOGIN. Field names are unique within an flist. Applications must use this name to refer to the field.

    The default fields used in BRM start with PIN_FLD_. You can use a different prefix for your custom fields to distinguish them from the default fields.

  • A type that specifies its data type and defines the range of values it can accept. For example, PIN_FLDT_STR for string type.

    For information on the BRM data types, see "Understanding the BRM Data Types"

  • Permission, which specifies if the field is optional, mandatory, writable, and so on.

  • An ID number that establishes it in the data dictionary. When you define a new field, the field is added to the data dictionary and is assigned the next consecutive ID number in the ranges reserved for customer use. For example, if the ID of the last field you created is 10,500, your new field's ID number will be 10,501.

    The following table lists the field ID ranges for Oracle-only use and for customer use:

    Table 3-2 BRM Field ID Restrictions

    Field ID Range Reserved For

    0 through 9999

    Oracle use only

    10,000 through 999,999

    Customer use

    1,000,000 through 9,999,999

    Oracle use only

    Over 10,000,000

    Customer use


For information on creating fields, see the Storable Class Editor Help.

Fields Common to All Storable Classes

Every BRM storable class requires the following fields for its storable object to be created in the system:

  • PIN_FLD_POID, which contains the POID. See "Portal Object ID (POID)" for more information.

  • PIN_FLD_NAME, which contains the name of the class.

  • PIN_FLD_CREATED_T, which contains the date the object was created.

  • PIN_FLD_MOD_T, which contains the date the object was modified.

  • PIN_FLD_READ_ACCESS, which specifies the read permissions for the object.

  • PIN_FLD_WRITE_ACCESS, which specifies the write permissions for the object.

These fields are available to the BRM applications and Facilities Modules (FMs), but you cannot write to them. They can be manipulated only by a Data Manager (DM).

Defining New Fields for Storable Classes

You define new fields and add them to the data dictionary by using the Storable Class Editor. After you define a field, you use the PIN_FLD_MAKE macro to create an encoded number for the field. You use this number to build flists for opcode and object manipulation in C code. The PIN_FLD_MAKE macro is defined in BRM_Home/include/pcm.h, where BRM_Home is the directory in which you installed BRM components.

For information on how to define fields, see the Storable Class Editor Help. For more information on creating custom fields and storable classes, see "Creating Custom Fields".

For information on defining new fields in C++, see "Creating Custom Fields".

For information on defining new fields in Java, see "Using Custom Fields in Java Applications".

Reading Objects

There are two ways to read the contents of storable objects in a BRM database:

Reading Objects by Using Opcodes

You can read storable objects in the database by using the read operations included in BRM. These opcodes are optimized for the most frequently used operations in BRM. You can read only a portion of the fields in a storable object instead of the complete object.

Use one of these opcodes to read objects:

Improving Performance when Reading Objects

To improve performance when reading objects by using PCM_OP_READ_OBJ and PCM_OP_READ_FLDS, set the PCM_OPFLG_CACHEABLE flag. See "Improving Performance when Working with Objects".

Locking Objects when Reading them

You can lock an object to avoid an extra round trip to the database. To lock an object while the PCM_OP_READ_OBJ or PCM_OP_READ_FLDS opcode reads it, use the PCM_OPFLG_LOCK_OBJ flag. The query is turned into the equivalent of a select for update, which places an exclusive lock on the rows in the database.

When using the PCM_OPFLG_LOCK_OBJ flag during an opcode process, the flag works as follows:

  • If the Facilities Module (FM) opcode opens a read/write transaction, the PCM_OPFLG_LOCK_OBJ flag locks the object for a PCM_OP_READ_OBJ or PCM_OP_READ_FLDS operation.

  • If the FM opcode opens a read-only transaction and then tries to use PCM_OPFLG_LOCK_OBJ in any subsequent read calls, the DM returns an error.

  • If the FM opcode does not open a transaction and then tries to use PCM_OPFLG_LOCK_OBJ in any subsequent read calls, the DM returns an error.

Improving Performance when Locking Objects

Most opcode operations lock the account when they begin processing. Though this provides reliable data consistency, locking an account locks all of its associated objects and can prevent other opcodes from operating on them. This can decrease the throughput of the system. To alleviate this problem in affected systems, you may choose to lock the specific objects an opcode will change instead of the whole account; the objects an opcode does not change can still be accessed by other opcodes. See "Locking Specific Objects".

Reading an Entire Object

To read an entire storable object from the database, use the PCM_OP_READ_OBJ opcode. Specify the POID of the object to read in the input flist. The POID of the object and all fields in the object return, including array elements and substructures.

Audit trail information

PCM_OP_READ_OBJ checks for an audit flag to see whether the read request is for an audited object. If an audit flag is set in the call to this opcode, a search for the audit trail is performed.

For information about accessing audit trails, see "Accessing Audit Trail Information".

When a field is marked for auditing, a shadow object is created every time the field is modified. A shadow object is a replica of the original object that contains the POID revision number of the object before it was modified.

For more information about shadow objects, see "About Shadow Objects".

To retrieve audit-trail revisions from the database, use these flags in the call to this opcode to send a request to the database DM:

  • PCM_OPFLG_USE_POID_GIVEN

    Executes a search-and-read operation for the POID you specify, which is the POID of the shadow object in the audit trail.

  • PCM_OPFLG_USE_POID_NEAREST

    Executes a search-and-read operation for the audit-trail revision number that you specify (the POID of the shadow object). If the exact POID is not found, it finds the POID with the revision number immediately preceding the revision number of the POID you specify.

  • PCM_OPFLG_USE_POID_NEXT

    Executes a search-and-read operation for the shadow object POID that contains the revision number next higher than the revision number in the POID you specify.

  • PCM_OPFLG_USE_POID_PREV

    Executes a search-and-read operation for the shadow object POID that contains the revision number immediately preceding the revision number in the POID you specify.

Reading Fields in an Object

To read one or more fields in a storable object, use the PCM_OP_READ_FLDS opcode. This opcode returns the POID of the object from which the fields were read, along with the specified fields and their values.

PCM_OP_READ_FLDS allows a client application to read specified fields in a storable object. Specify the POID of the storable object along with the list of fields to be read in the input flist. The POID is mandatory; the fields are optional. If there are no fields present, only the POID is read and returned.

To read an array element, specify the element in the input flist. If the array element contains a substructure that contains fields you want to read, you must also specify the substruct elements in the input flist.

Note:

To improve performance, some storable object arrays are stored in a special serialized format. When a client application requests fields from a serialized array, PCM_OP_READ_FLDS returns the entire array rather than just the specified fields.

You can read all the fields of a substructure or array in the following ways:

  • To read an entire substruct, put the substruct field in the input flist with a NULL value.

  • To read all the fields in an array element, put the array element in the input flist with a NULL value. This returns all fields, including those from substructs.

  • To read all the elements of an array, put the array element in the input flist with an element ID of PIN_ELEMID_ANY.

Examples

  • This opcode can be used with a read-only transaction to obtain a frozen view of an object. When a read-only transaction is open, all reads are performed on fields in the state they are in when the transaction is opened. This is an important consideration when you perform multiple reads and must ensure that the data does not change between reads, such as when adding up fields for a balance.

    For information about opening a read-only transaction, see "PCM_OP_TRANS_OPEN" in BRM Developer's Reference.

  • You can use this opcode to find the value of a flag. This example shows the input and output flists for reading the value of the PIN_FLD_FLAGS field in the PIN_FLD_BALANCES array element in a /balance_group object:

    CM input flist: op PCM_OP_READ_FLDS, flags 0x0
    # number of field entries allocated 20, used 2
    0 PIN_FLD_POID                 POID [0] 0.0.0.1 /balance_group 685398 3
    0 PIN_FLD_BALANCES            ARRAY [840] allocated 20, used 1
    1     PIN_FLD_CREDIT_PROFILE    INT [0] 0
      
    CM output flist: op PCM_OP_READ_FLDS
    # number of field entries allocated 20, used 2
    0 PIN_FLD_POID                 POID [0] 0.0.0.1 /balance_group 685398 1
    0 PIN_FLD_BALANCES            ARRAY [840] allocated 20, used 1 
    1     PIN_FLD_CREDIT_PROFILE    INT [0] 22
    

Reading Objects by Using Object Browser

Use Object Browser, part of Developer Center, to view storable objects in the BRM database. You can see a list of all the objects in a class as well as the contents of objects that you select. You can also save and print object contents. For complete instructions, see the Object Browser Help.

For more information about Developer Center, see "About Developer Center".

Starting Object Browser

To start Object Browser:

  1. Start Developer Center and log in to the database schema you want to use.

    See "About Developer Center" for instructions.

  2. Click the Object Browser toolbar button or choose Tools - Object Browser.

Viewing an Object in the Database

To view an object in the database:

  1. Enter or choose a class name and then click Browse.

    A list of storable objects appears in the Objects area.

  2. Select a storable object in the list of objects.

    The contents of the object are displayed as an flist.

Disabling Granular Object Locking

By default, granular object locking is enabled in BRM. You can disable this feature by modifying the LockConcurrency field in the multi_bal instance of the /config/business_params object.

The default behavior, which corresponds to the LockConcurrency value of high, allows you to call opcodes with the PCM_OPFLG_LOCK_OBJ and PCM_OPFLG_LOCK_DEFAULT flags to determine the locking procedure. See "Locking Specific Objects".

When you disable granular locking, the following rules apply:

  • There is no differentiation of the PCM_OPFLG_LOCK_OBJ and PCM_OPFLG_LOCK_DEFAULT flags.

  • A given balance group object will be locked as is.

  • All other objects will be translated to lock its associated account (if any).

  • The root or master login account will be ignored.

  • The object that has no account association will be locked as is.

Performance is better when you use granular object locking.

You modify the /config/business_params object by using the pin_bus_params utility.

To disable granular object locking:

  1. Use the following command to create an editable XML file from the multi_bal instance of the /config/business_params object:

    pin_bus_params -r multi_bal financial/config/xml_utils/bus_params_multi_bal.xml
      
    

    This command creates the XML file named financial/config/xml_utils/bus_params_multi_bal.xml.out in your working directory. If you do not want this file in your working directory, specify the path as part of the file name.

  2. Search the XML file for following line:

    <LockConcurrency>high</LockConcurrency>
      
    
  3. Change high to normal.

    Caution:

    BRM uses the XML in this file to overwrite the existing multi_bal instance of the /config/business_params object. If you delete or modify any other parameters in the file, these changes affect the associated aspects of the BRM multischema configuration.
  4. Save the file with the file name financial/config/xml_utils/bus_params_multi_bal.xml.

  5. Use the following command to load this change into the /config/business_params object:

    pin_bus_params financial/config/xml_utils/bus_params_multi_bal.xml
      
    

    You should execute this command from the BRM_Home/sys/data/config directory, which includes support files used by the utility.

  6. Read the object with the testnap utility or the Object Browser to verify that all fields are correct.

  7. Stop and restart the Connection Manager (CM). For more information, See "Starting and Stopping the BRM System" in BRM System Administrator's Guide.

  8. (Multischema systems only) Run the pin_multidb script with the -R CONFIG parameter. For more information, see pin_multidb in BRM System Administrator's Guide.

Creating, Editing, and Deleting Objects

Use the following opcodes to create, edit, and delete objects:

Creating Objects

To create an object, use the PCM_OP_CREATE_OBJ opcode. This opcode creates a new storable object of the type specified in the input flist. You must specify the database type and class type subfields of the object POID on the input flist. The POID ID is ignored unless you use the PCM_OPFLG_USE_POID_GIVEN flag.

The PCM_OP_CREATE_OBJ input flist must include all the fields that the storable object requires. The fields required in the input flist depend on the type of object; for example, an /account object includes security code, account number, account type, balances, and credit fields.

This opcode returns the POID of the object created. If you use the PCM_OPFLG_READ_RESULT flag, it also returns all fields from the created object, including array elements and substructures.

Flags

  • PCM_OPFLG_USE_POID_GIVEN

    If you use the PCM_OPFLG_USE_POID_GIVEN flag, PCM_OP_CREATE_OBJ uses the POID ID you specify on the input flist. If the ID is a duplicate, a new POID ID is assigned. If you do not use the PCM_OPFLG_USE_POID_GIVEN flag, this opcode assigns a new POID ID.

    Not all storable object POID IDs can be assigned by a user. For information on which storable object POID IDs can be assigned, see the object specifications in "Storable Class Definitions" in BRM Developer's Reference.

  • PCM_OPFLG_READ_RESULT

    Returns all fields from the created object, including array elements and substructures.

  • PCM_OPFLG_CACHEABLE

    Enables caching each transaction's objects in the Connection Manager (CM) instead of writing them immediately to the database. See "Improving Performance when Working with Objects".

    If the PCM_OPFLG_CACHEABLE flag is not set, the opcode writes the input flist to the database immediately and writes it to the cache for future use.

Writing Fields in Objects

To write fields in an object, use the PCM_OP_WRITE_FLDS opcode. This opcode returns the POID of the object whose fields were written, including the new revision number. This opcode allows a client application to set the values of fields in a storable object. Specify the fields and values to set, along with the POID of the object, on the input flist. You must update at least one field.

The field values are absolutely set to the values you provide. To make a relative change to a numeric field value, use the PCM_OP_INC_FLDS opcode.

Update array element fields by specifying the array element ID and the field element ID in the input flist. If there is no array element for the fields you want to update, you must create the element by using the PCM_OPFLG_ADD_ENTRY flag.

Note:

This flag is required because BRM allocates space for array elements only when they are created and assigned a value. If you do not use the PCM_OPFLG_ADD_ENTRY flag, you receive an error when you try to update array fields in an element that doesn't exist.

The PCM_OPFLG_ADD_ENTRY flag is required only for array fields. Fields that are not part of an array element must already exist (assuming the storable object exists) so they are updated as requested.

If you set an array element in the input flist and use the element ID PIN_ELEMID_ASSIGN, the element is created with an element ID numbered next higher than the highest existing element ID for that array.

Not all fields in each storable object are writable by the application. For details on which fields are writable, see "Storable Class Definitions" in BRM Developer's Reference.

Flags

  • PCM_OPFLG_ADD_ENTRY

    Creates an array element and updates fields as requested. If the array element already exists, this flag is ignored. PCM_OPFLG_ADD_ENTRY cannot be used to create ordinary fields.

  • PCM_OPFLG_READ_RESULT

    Returns all fields from the created object, including array elements and substructures.

  • PCM_OPFLG_NO_RESULTS

    Although this flag can be included, the PCM_OP_WRITE_FLDS opcode ignores it and returns the POID.

  • PCM_OPFLG_CACHEABLE

    Enables caching each transaction's objects in the CM instead of writing them immediately to the database. See "Improving Performance when Working with Objects".

    If the PCM_OPFLG_CACHEABLE flag is not set, the opcode writes the input flist to the database immediately and writes it to the cache for future use.

    If an array element in the input flist has an element ID of PIN_ELEM_ID_ASSIGN, the element is not cached, even if the PCM_OPFLG_CACHEABLE flag is set.

    If neither PCM_OPFLG_CACHEABLE nor PCM_OPFLG_ADD_ENTRY is set, and the array entry does not exist, the opcode fails. If PCM_OPFLG_CACHEABLE is set but PCM_OPFLG_ADD_ENTRY is not set, and the array entry does not exist, the opcode also fails, but it does not return the error immediately. The delayed error appears when the fields are actually written to the database.

Incrementing Fields in Objects

To increment fields in an object, use the PCM_OP_INC_FLDS opcode. This opcode returns the POID of the object whose fields were updated, including the new revision number. It also returns the revised values of the selected fields unless the PCM_OPFLG_NO_RESULTS flag is used.

This opcode increments or decrements fields specified in the input flist. Only fields of type PIN_FLDT_INT and PIN_FLDT_DECIMAL can be incremented or decremented, and both types must be signed in the input flist. The signed value of the field in the input flist determines whether the field is incremented or decremented.

You must update at least one field. Specify the POID of the object that contains the fields to update, along with at least one field, in the input flist.

Update array element fields by specifying the array element ID along with the field element ID in the input flist. If there is no array element for the fields you want to update, you must create the element by using the PCM_OPFLG_ADD_ENTRY flag.

Note:

This flag is required because BRM allocates space for array elements only when they are created and assigned a value. If you do not use the PCM_OPFLG_ADD_ENTRY flag, you receive an error when you try to update array fields in an element that doesn't exist. An error also occurs if the array contains any non-incremental fields or mandatory fields of a non-incremental type.

The PCM_OPFLG_ADD_ENTRY flag is required only for array fields. Fields that are not part of an array element must already exist (assuming the storable object exists) so they are updated as requested.

If you set an array element on the input flist and assign the element ID a value of PIN_ELEMID_ASSIGN, the element is created with an element ID that is numbered next higher than the highest existing element ID for that array.

Updating Decimal Data Types

When you increment or decrement fields of decimal data type, the result depends on the value of the field both in the database and in the input flist. If the value of the field in the database is NULL, BRM converts that value to 0 before updating. If the value of the field in the input flist is NULL or 0, no action is taken on the value in the database. This prevents a non-NULL value in the database from being converted to NULL.

Table 3-3 shows the three possible results of an increment (0, NULL, or non-NULL) for all possible field value combinations. These results apply only to decimal data types:

Table 3-3 Incrementing Database Field Values

Database Field Value Flist Increment Value Result of Increment

NULL

NULL or 0

NULL

NULL

Non-NULL

Non-NULL

0

NULL or 0

0

0

Non-NULL

Non-NULL

Non-NULL

NULL or 0 or non-NULL

Non-NULL


If you want a field value to remain open (such as a credit limit), you should increment the field by a value of either 0 or NULL.

You can prevent the conversion of the field value in the database from NULL to 0 by using the PCM_OPFLG_USE_NULL flag. This flag assigns a NULL value to the field in the input flist, which prevents a change to the database value.

Updating Integer Data Types

You cannot assign a NULL value to fields of type INT in the input flist. If you update an INT data type, the PCM_OPFLG_USE_NULL flag is ignored. To maintain a NULL value in the database for a field of type INT, you must increment with 0. If the increment value is non-zero in the input flist, the result is always non-zero.

Not all fields in each storable object can be incremented by an application. For information on which fields can be incremented, see "Storable Class Definitions" in BRM Developer's Reference.

Flags

  • PCM_OPFLG_ADD_ENTRY

    Creates an array element, if it doesn't already exist, and updates the specified fields as requested. It cannot be used to create non-array fields. If the array element already exists, this flag is ignored.

  • PCM_OPFLG_READ_RESULT

    Returns all fields from the created object, including array elements and substructures.

  • PCM_OPFLG_USE_NULL

    Prevents a NULL field value in the database from being converted to 0 and updated.

  • PCM_OPFLG_NO_RESULTS

    Returns only the POID, without the updated data. This flag provides higher performance by skipping the extra processing of returning updated data.

Deleting Objects

To delete an object, use the PCM_OP_DELETE_OBJ opcode. Specify the POID of the storable object to delete in the input flist. This opcode ignores the field values of the object to be deleted. When a storable object is deleted, its POID ID cannot be reused.

This opcode deletes only the storable object passed in. No integrity checks are performed to ensure that the storable object is not referenced in any way.

Important:

To maintain database consistency, you must make sure that your application deletes any other storable objects that reference or are referenced by the storable object you delete.

This opcode returns the POID of the deleted object.

Deleting Fields in Objects

To delete fields in an object, use the PCM_OP_DELETE_FLDS opcode. This opcode returns the POID of the object from which an element was deleted, including the new revision number.

You must delete at least one array element. Specify the POID of the object from which to delete elements in the input flist. Also specify the array element ID for each element to be deleted. To delete an entire array, put the array in the input flist and use the element ID PCM_RECID_ALL.

The value for each array element to be deleted must be NULL. The value of fields within an array element to be deleted are ignored. You cannot delete fields within an array element without deleting the array element.

Only optional arrays and array elements can be deleted. Attempting to delete a mandatory element will return an error. You cannot delete fields that are not part of an array element, and you cannot delete arrays or array elements within a substructure.

For a list of fields that can be deleted, see the relevant object specifications in "Storable Class Definitions" in BRM Developer's Reference.

Managing a Large Number of Objects

In addition to working with individual objects, you can use base opcodes to perform the following operations on a large number of objects in one database operation instead of accessing the database for every object:

Creating a Large Number of Objects

To create a large number of storable objects of the same type, use the PCM_OP_BULK_CREATE_OBJ opcode.

The PCM_OP_BULK_CREATE_OBJ input flist must include all the fields that the objects of the storable class requires. The required input flist fields depend on the type of objects that you are creating; for example, an /account object includes security code, account number, account type, balances, and credit fields. You can use the PIN_FLD_COMMON_VALUES array in the input flist for fields that have common values for all objects being created.

Note:

You cannot use this opcode to create a new storable class. You can use it only to create objects in an existing storable class.

You can use the same flags with this opcode as you can with the PCM_OP_CREATE_OBJ opcode, except that the following flags are not supported:

  • PCM_OPFLG_USE_POID_GIVEN

  • PCM_OPFLG_READ_RESULT

This opcode returns the type-only POID of the objects created, but it does not return the full POIDs of the individual objects created.

Editing a Large Number of Objects

To update fields in a large number of storable objects of the same type, use the PCM_OP_BULK_WRITE_FLDS opcode.

This opcode updates the values of the fields or adds new fields in the objects that meet the conditions you specify in the input flist. It returns the POID type and count of the objects.

To update array element fields, specify the array element ID and the field element ID in the input flist. You can update first- and second-level array fields. If there is no array element for the fields you want to update, you must create the element by using the PCM_OPFLG_ADD_ENTRY flag.

Note:

This flag is required only for array elements because BRM allocates space for array elements only when they are created and assigned a value. If you do not use the PCM_OPFLG_ADD_ENTRY flag, you receive an error when you try to update array fields in an element that doesn't exist.

Fields that are not part of an array element must already exist for an object, and they are updated.

If you set an array element in the input flist and use the element ID PIN_ELEMID_ASSIGN, the element is created with an element ID higher than the highest existing element ID for that array.

Deleting a Large Number of Objects

To delete a large number of storable objects of the same type, use the PCM_OP_BULK_DELETE_OBJ opcode. This opcode deletes the objects of the type that meet the conditions you specify in the where clause of the query. It returns the POID type and the count of the objects deleted.

Note:

  • You cannot use the opcode to delete specific fields in an object, only to delete complete objects.

  • You cannot use the opcode to delete an entire storable class, only to delete objects in that class.

Locking Objects when Editing or Deleting a Large Number of Objects

To enforce the data integrity of bulk operations (the PCM_OP_BULK_WRITE_FLDS and PCM_OP_BULK_DELETE_OBJ opcodes), specify the PCM_OPFLG_LOCK_OBJ flag for the opcodes.

Note:

The PCM_OP_LOCK_DEFAULT flag is ignored by the bulk opcodes.

When the PCM_OPFLG_LOCK_OBJ flag is specified, the balance groups of the known objects or the unknown objects will be locked. The rules for identifying which balance groups are locked are identical to the rules used in "Locking Specific Objects".

Improving Performance when Working with Objects

Some of the opcodes used for searching and manipulating objects use the PCM_OPFLG_CACHEABLE flag. This flag enables caching each transaction's objects in the Connection Manager (CM) instead of writing them immediately to the database. Caching makes both the CM and the DM more efficient because the CM doesn't request the data Manager (DM) to write the same object to the database multiple times.

Objects to be written are cached until the end of the transaction unless they need to be written to the database earlier. For example, a search causes immediate execution of all pending writes, so the search can work on the most current data.

If the PCM_OPFLG_CACHEABLE flag is not set, the opcode writes the input flist to the database immediately and writes it to the cache for future use.

The CM writes flist fields to the database when the application does the following:

  • Executes one of the following opcodes:

    • PCM_OP_CREATE_OBJ

    • PCM_OP_SEARCH

    • PCM_OP_STEP_SEARCH

    • PCM_OP_STEP_NEXT

    • PCM_OP_GLOBAL_SEARCH

    • PCM_OP_GLOBAL_STEP_SEARCH

    • PCM_OP_GLOBAL_STEP_NEXT

    • PCM_OP_READ_OBJ

    • PCM_OP_READ_FLDS

    • PCM_OP_WRITE_FLDS

  • Executes PCM_OP_INC_FLDS and the fields are part of the object in writable cache.

Sometimes, the object can be partially available in the cache due to previous executions of PCM_OP_READ_FLDS or PCM_OP_WRITE_FLDS. If the partial object is in read-only cache, the CM destroys it and reads a complete object from the database through the DM. The CM caches that object before returning it to the application. If the partial object has been updated and therefore is in the writable cache, the CM writes it to the database before reading and caching the complete object.

The scope of a transaction cache is one transaction.

Note:

Transaction caching is not always beneficial. For example, if a transaction reads a given object only once, it should not use the PCM_OPFLG_CACHEABLE flag.

Locking Specific Objects

Locking on an account level (higher object hierarchy) can cause contention between opcodes and therefore create a bottleneck, reducing the throughput of the BRM system. Because the default locking process locks at the account level, performance can be improved by locking only the working objects rather than the account.

You can lock balance groups for the specific operations that are impacting performance. If you do not specify a more granular locking procedure, transactions lock account objects; no code change is required.

There are some frequently used operations that can take advantage of granular locking on balance group objects. They may lock the object's default or associated balance group to improve performance.

Important:

Exercise caution when customizing locking strategies. Changes to lower-level locking on balance group objects may cause a deadlock if you are not familiar with the execution paths of the Facilities Module (FM) utility subroutines.

BRM supports balance group locking for transactions and opcodes that open the following known objects:

  • A given account

  • A given service

  • A given group

  • A given billinfo

  • A given bill

  • A given balance group

  • A given profile

  • A given reservation (including /reservation/active)

  • A given reservation list

  • A purchased product

  • A purchased discount

  • An event

  • A journal

You use the following flags to lock balance groups:

  • Use the PCM_TRANS_OPEN_LOCK_OBJ flag to lock all the associated balance groups (multiple balance groups) during the opening of a transaction. The equivalent flag for use with the other base opcodes is PCM_OPFLG_LOCK_OBJ.

    For example:

    fm_utils_trans_open(ctxp, opflags|PCM_TRANS_OPEN_LOCK_OBJ, pdp, ebufp);
      
    
  • Use the PCM_TRANS_OPEN_LOCK_DEFAULT flag to lock the default balance group during the opening of a transaction. The equivalent flag for use with the base opcode is PCM_OPFLG_LOCK_DEFAULT.

    For example:

    PCM_OP(ctxp, PCM_OP_READ_FLDS, PCM_OPFLG_LOCK_OBJ, s_flistp, &o_flistp, ebufp);
      
    

Using these flags can improve your system's performance if many balance groups are associated with the object you are targeting with the lock request. Each flag locks balance groups according to the object type opened by the opcode or utility as shown in Table 3-4:

Table 3-4 Balance Locking Flags

Object Types PCM_TRANS_OPEN_LOCK_OBJ PCM_TRANS_OPEN_LOCK_DEFAULT

Account

Generate a SQL template to do bulk locking on all the account's balance groups.

Lock the account's default balance group.

BillInfo

Generate a SQL template to do bulk locking on all the bill unit's balance groups.

Lock the bill unit's default balance group.

Balance Group

Lock the balance group.

Note: This rule is identical to that of PCM_TRANS_OPEN_LOCK_DEFAULT.

Lock the balance group.

Service

Lock the service's default balance group.

Note: This rule is identical to that of PCM_TRANS_OPEN_LOCK_DEFAULT.

Lock the service's default balance group.

Profile

Lock all the parent account's balance groups (alternatively).

Note: There may be some ambiguity in this rule.

Lock the parent's default balance group.

Group

Lock all the owner account's balance groups.

Lock the owner account's default balance group.

Bill

Lock all bill unit's balance groups.

Lock the bill unit's default balance group.

Reservation

Lock the reservation's default balance group.

Note: This rule is identical to that of PCM_TRANS_OPEN_LOCK_DEFAULT.

Lock the reservation's default balance group.

Reservation/active

Determine the reservation list using the POID of the default balance group and lock the reservation list.

Note: This rule is identical to that of PCM_TRANS_OPEN_LOCK_DEFAULT.

Determine the reservation list using the POID of the default balance group and lock the reservation list.

Item

Lock the item's default balance group.

Note: This rule is identical to that of PCM_TRANS_OPEN_LOCK_DEFAULT.

Lock the item's default balance group.

Reservation List

Lock the reservation-list object as is by returning its POID.

Note: This rule is identical to that of PCM_TRANS_OPEN_LOCK_DEFAULT.

Lock the reservation-list object as is by returning its POID.

Journal

Lock the journal object as is by returning its POID.

Note: This rule is identical to that of the PCM_TRANS_OPEN_LOCK_DEFAULT

Lock the journal object as is by returning its POID.

Event

Lock the event object as is by returning its POID.

Note: This rule is identical to that of PCM_TRANS_OPEN_LOCK_DEFAULT.

Lock the event object as is by returning its POID.

Purchased Product

Lock all of the service's default balance groups (if any) or parent account's default balance groups (alternatively).

Note: This rule is identical to that of PCM_TRANS_OPEN_LOCK_DEFAULT.

Lock the all the service's default balance groups (if any) or parent account's default balance groups (alternatively).

Purchased Discount

Lock all of the service's default balance groups (if any) or parent account's default balance groups (alternatively).

Note: This rule is identical to that of PCM_TRANS_OPEN_LOCK_DEFAULT.

Lock the all the service's default balance groups (if any) or parent account's default balance groups (alternatively).

Active Session

Objects of this kind will never be locked. The lock request will be ignored.

Note: This is a temporary rule and may be revoked in the further. It is recommended that you remove code to lock the active session object.

Objects of this kind will never be locked. The lock request will be ignored.

Others

Lock all the balance groups of the parent account, provided the account is not the root or the PCM login account. Otherwise, lock the object as is.

Note: BRM assumes that the login user ID is an account POID.

Lock the default balance group of the parent account provided that the account must not be the root or the PCM login account. Otherwise, lock the object as is.


Important:

When using either flag, be aware of what is locked and what is not locked. A deadlock can occur when two different transaction contexts lock on a common set of objects and the lock sequences are not synchronized.

Oracle can detect the database-level deadlocks and throws an error to the DM. Users may also dump the CM lock map to determine the object that caused the deadlock. The technique is as follows:

  1. Obtain the lock map flist using PCP_GET_TRANS_FLIST.

  2. Use PIN_ERR_LOG_FLIST to display the lock map flist.

There are many opcodes that can lock based on the objects in the list. In some cases, it should be okay to leave things as they are. If you decide not to change anything, things should still work as before and performance should not degrade.

Some sample strategies that may be employed to assist performance are:

  • Change PCM_OPFLG_LOCK_OBJ to PCM_OPFLG_LOCK_ DEFAULT in an operation you already use. This may change its locking behavior but typically if you were not experiencing deadlocks with this operation before, it can be changed safely.

  • Change the object to lock. If an opcode works on only the /service object, try using the PCM_OPFLG_LOCK_DEFAULT flag on the /service object if it is provided in the input flist. In this way, objects that are not changed are not locked and therefore a given opcode will not interfere with objects that it does not change.

You can lock only when you are in a read-write transaction. Otherwise, your lock flags will be ignored or may result in a fatal PCM error.