Você está na página 1de 183

DataFlex® 3.

2
Data Dictionary Guide
Copyright © 2000 Data Access Corporation

DATA ACCESS CORPORATION


Miami, Florida USA

Technical support: (voice) 305.232.3142


(FAX) 305.238.0017

Internet: World Wide Web at URL http://www.dataaccess.com/


Revision Date: July 10, 2000
DataFlex 3.2 Data Dictionary Guide

COPYRIGHT NOTICE

Copyright 2000 DATA ACCESS CORPORATION. All rights reserved.

No part of this publication may be copied or distributed, transmitted, transcribed, stored in


a retrieval system, or translated into any human or computer language, in any form or by
any means, electronic, mechanical, magnetic, manual, or otherwise, or disclosed to third
parties without the express written permission of Data Access Corporation, Miami,
Florida, USA.

DISCLAIMER
Data Access Corporation makes no representation or warranties, express or implied, with
respect to this publication, or any Data Access Corporation product, including but not
limited to warranties of merchantability or fitness for any particular purpose.

Data Access Corporation reserves to itself the right to make changes, enhancements,
revisions and alterations of any kind to this publication or the product(s) it covers without
obligation to notify any person, institution or organization of such changes,
enhancements, revisions and alterations.

TRADEMARKS
DataFlex is a registered trademark of Data Access Corp.

Visual DataFlex is a trademark of Data Access Corp.

FlexQL is a trademark of Data Access Corp.

All other company, brand, and product names are registered trademarks or trademarks of
their respective holders.

-2-
DataFlex 3.2 Data Dictionary Guide

Contents
Using Data-Dictionary Objects .........................................................................................................6
What DDOs Do .............................................................................................................................6
The DataDictionary Class .............................................................................................................6
How Data Dictionaries Work ....................................................................................................7
Building Data-Dictionary Structures ...........................................................................................54
Propagation of Data-Dictionary Operations ............................................................................56
Connecting More Than One DDO to the Same File................................................................64
Using System Files in Data Dictionaries .................................................................................65
Constraints...................................................................................................................................67
The Constrain Command.........................................................................................................67
Programming Constraints in DDOs.........................................................................................68
Variable Constraints................................................................................................................69
Constraint Search Optimization...............................................................................................69
Advanced Data-Dictionary Topics ..............................................................................................70
“Picture” Masking for Display and Data Entry .......................................................................70
Controlling “Cascading” Deletions .........................................................................................75
Smart Data-File Locking .........................................................................................................76
Refresh Mechanism.................................................................................................................81
The Data-Dictionary Operation Integers .................................................................................83
Auto-fill and Data Dictionaries ...............................................................................................85
Saving and Deleting ................................................................................................................85
Validation and Constraints ......................................................................................................85
Item Validation........................................................................................................................85
Controlling DDO Connections ................................................................................................88
Sample Data-Dictionary Code.....................................................................................................91
Customer.dd ............................................................................................................................91
Vendor.dd................................................................................................................................94
Salesp.dd .................................................................................................................................96
Invt.dd .....................................................................................................................................98
OrderHea.dd..........................................................................................................................100
Orderdtl.dd ............................................................................................................................104
Character Mode Data Dictionary Class Reference ........................................................................106
DataDictionary ..........................................................................................................................106
Source....................................................................................................................................106
Purpose..................................................................................................................................106
Hierarchy...............................................................................................................................107
Usage.....................................................................................................................................107
-3-
DataFlex 3.2 Data Dictionary Guide

Of Special Note .....................................................................................................................108


Properties ..............................................................................................................................118
Methods.................................................................................................................................132
File_field Messages...............................................................................................................156
Commands.............................................................................................................................157
ValidationTable.........................................................................................................................158
Purpose..................................................................................................................................158
Hierarchy...............................................................................................................................158
Source....................................................................................................................................158
Usage.....................................................................................................................................158
Of Special Note .....................................................................................................................159
Properties ..............................................................................................................................159
Methods.................................................................................................................................160
DescriptionValidationTable ......................................................................................................161
Purpose..................................................................................................................................161
Hierarchy...............................................................................................................................161
Source....................................................................................................................................161
Usage.....................................................................................................................................161
Of Special Note .....................................................................................................................161
Properties ..............................................................................................................................162
Methods.................................................................................................................................162
FileValidationTable...................................................................................................................162
Purpose..................................................................................................................................162
Hierarchy...............................................................................................................................162
Source....................................................................................................................................162
Usage.....................................................................................................................................162
Of Special Note .....................................................................................................................163
Properties ..............................................................................................................................163
Methods.................................................................................................................................164
CodeValidationTable ................................................................................................................164
Purpose..................................................................................................................................164
Hierarchy...............................................................................................................................164
Source....................................................................................................................................164
Sample...................................................................................................................................165
Usage.....................................................................................................................................165
Of Special Note .....................................................................................................................165
Properties ..............................................................................................................................166
Methods.................................................................................................................................166
ValidationList............................................................................................................................166
Purpose..................................................................................................................................166
Hierarchy...............................................................................................................................166
Source....................................................................................................................................166
-4-
DataFlex 3.2 Data Dictionary Guide

Usage.....................................................................................................................................166
Of Special Note .....................................................................................................................167
Properties ..............................................................................................................................167
Methods.................................................................................................................................168
BusinessProcess ........................................................................................................................168
Purpose..................................................................................................................................168
Hierarchy...............................................................................................................................168
Source....................................................................................................................................168
Sample...................................................................................................................................168
Syntax....................................................................................................................................169
Of Special Note .....................................................................................................................170
Properties ..............................................................................................................................172
Events....................................................................................................................................174
Methods.................................................................................................................................174
StatusPanel ................................................................................................................................177
Purpose..................................................................................................................................177
Hierarchy...............................................................................................................................178
Source....................................................................................................................................178
Syntax....................................................................................................................................178
Usage.....................................................................................................................................178
Of Special Note .....................................................................................................................178
Properties ..............................................................................................................................179
Methods.................................................................................................................................179
StatusdbLog...............................................................................................................................181
Purpose..................................................................................................................................181
Hierarchy...............................................................................................................................181
Source....................................................................................................................................181
Syntax....................................................................................................................................181
Of Special Note .....................................................................................................................181
Events....................................................................................................................................182
Methods.................................................................................................................................182

-5-
DataFlex 3.2 Data Dictionary Guide

Using Data-Dictionary Objects


This chapter covers the internals of data-dictionary objects (DDOs) in manipulation of the
database on disk.

What DDOs Do
DDOs serve two purposes: they coordinate database activity among data-entry objects
(DEOs), and they provide database validation and update services to a program. These
two purposes are distinct. Coordinated database activity is provided by creating a
structure of DDOs, properly connecting the objects together (with set ddo_server
dependencies and constraints) and properly connecting DEOs to this structure (with set
server dependencies). You program all this at the object level. Database rules are
maintained and enforced by creating various data-dictionary hook procedures and
functions inside data-dictionary classes. You program this at the class level. Working with
DDOs consists of:

1. Creating a data-dictionary subclass for each data file, naming the data file as
the main_file, and coding database rules in these classes’ properties,
functions and procedures (e.g., define_fields, update, backout, creating,
validate_save, validate_delete).
2. Creating DDOs based on the classes created in Step 1.
3. Placing these objects inside views and connecting them to another DDO with
the set ddo_server message and connecting DEOs to the DDO structure
with the set server message.

The set ddo_server message connects a client DDO to a server DDO (child to parent).
This is sometimes referred to as an updating link. A group of DDOs are connected via
an updating structure.

The set server message connects a DEO to a DDO. This is sometimes referred to as a
using link. The DEO is using the services of its server (the DDO).

The DataDictionary Class


The DataDictionary class allows you to apply a set of rules to all the fields in a data file
without having to repeat those rules in every data-entry object (DEO) that accesses the
file. It is a subclass of DataSet and should be used in turn to create (at least) one
subclass for each file accessed in an application. The rules you can specify in the data
dictionary may alter the file’s structure; specify how it connects to other data files; what
field properties and validations apply, and what interdependencies exist between field
values in different data files.
-6-
DataFlex 3.2 Data Dictionary Guide

If you are new to object-oriented DataFlex, you will find data dictionaries extremely
powerful tools for standardizing data files and the ways they are used. If you already have
objects of the predecessor DataSet class in your programs, you may continue to do so
without using data dictionaries (not recommended); you may change them to use data
dictionaries, or you may use a combination (provided that you do not mix data sets and
data dictionaries within the same view).
How Data Dictionaries Work
The following sections explain how to use the DataDictionary class and its messages.
The DataFlex Class Reference explains all the messages and their syntaxes.
Defining Database Rules
Rules for a data file are defined within its data dictionary by the following steps, normally
in the subclass definition. Virtually all of these steps can be taken by using the Database
Builder, which generates the code for them.

1. Define all desired data-file properties. These are the properties that define
how the entire data file should behave. These properties include identifying
the main data file and all required parent and child files by their filenumbers,
and defining how saves and deletes should be processed.
2. Define all desired data-field properties. These are properties that are
specific to each particular data field. There are numerous field properties,
most of which specify how a field should be formatted; how it should appear;
how entries to it should be validated, and how item navigation should be
handled for the field.
3. Create any required validation, entry, and exit handlers. If you have
assigned validation, exit, or entry messages to any fields, you will need to
define the procedures and functions to support those messages. If a
validation table has been assigned to a field, you must create that validation-
table object (sometimes this will be within the DDO, and other times it will be
a global validation table that can be shared by other data dictionaries).
4. Create hook procedures and functions. During save and delete
operations, special “hook” messages are sent. By default, the handlers do
nothing. It is expected that you will define custom processing within these
procedures and functions as necessary.
5. They are used primarily for validation checking and for maintaining calculated
field values.
Setting Properties in Define_Fields

All file and field properties are set within the define_fields procedure. This procedure is
probably the most-important procedure in the data dictionary.

-7-
DataFlex 3.2 Data Dictionary Guide

Setting File Properties


The most-common file properties are:

Main_File

This identifies the file that the subclass is meant to handle. You must set a main_file
within your data dictionary. In older data-server classes, this property was set within a
procedure named construct_object. While this is still valid, you are encouraged to set
main_file within define_fields.

Example:
procedure define_fields
forward send define_fields
set main_file to customer.file_number
:

Add_Server_File / Add_Client_File

You add files to the required-parent-file list with the add_server_file message.
Add_client_file is used to add a file to the required-child-file list. Before a save or a
delete is processed, the data dictionary will note the files required and make sure that
there is a DDO within the data-dictionary structure for each file, and that they are
connected property. If not, the save or delete will not occur. This ensures that the data-
dictionary structure is complete. You only need to declare the immediate parent and child
files within the data dictionary. Grandparent and grandchild files will be linked in turn
through declarations in the parent- and child-file data dictionaries.

Example:
procedure define_fields
forward send define_fields
set main_file to orderhea.file_number
send add_server_file customer.file_number
send add_server_file sales.file_number
send add_client_file orderdtl.file_number
:

Add_system_file

The default behavior of saving or deleting is to lock and reread all open files in the file list
for the time required to save to disk. Data dictionaries support a feature named “smart
filemode” that can substantially improve the performance of saves and deletes. This is
controlled by the smart_filemode_state property. When all data dictionaries in a data-
dictionary structure set this property to true, only the data files that will actually participate
-8-
DataFlex 3.2 Data Dictionary Guide

in the operation will be locked and reread. If system files are controlled with an updating
link, they are covered, but if not, getting smart filemode to work properly with such files
requires you to declare them with the add_system_file message in the define_fields
procedure. In earlier revisions of DataFlex, this was more complicated and was achieved
with reset_filemodes_for_lock. The syntax of add_system_file is:

Send add_system_file file [lock_type]

Argument Explanation
file The name of the system file
lock_type Save/delete condition to lock this file.

This allows for very-smart locking, in which the file is only locked when absolutely needed
(e.g., during the save of a new record, but not during a delete or the save of an existing
record). Legal values are: DD_Lock_on_All, DD_Lock_on_Delete, DD_Lock_on_Save,
DD_Lock_on_New_Save, and DD_Lock_on_New_Save_Delete. If no lock_type is
given, lock_on_all is used.

Examples:

These two examples are the same:


Send Add_system_file ordsys
Send Add_system_file ordsys dd_lock_on_all

This example only locks for new saves, not deletes:


Send Add_system_file ordsys dd_lock_on_new_save

This example locks for all saves, not deletes:


Send Add_system_file ordsys dd_lock_on_Delete

This example locks for new saves and deletes (not on edits):
Send Add_system_file ordsys dd_lock_on_new_save_delete

Note: You can add multiple files by sending multiple messages:


Send Add_system_file ordsys1
Send Add_system_file ordsys2

You may remove a system file (which would rarely be done) with:
Send Remove_system_file ordsys
Cascade_delete_state

Cascade_delete_state specifies how a delete should be affected by the existence of


child-file records that relate to the record being deleted. If cascade_delete_state is true,
then the child records and all descendant records will be deleted. If the property is false,

-9-
DataFlex 3.2 Data Dictionary Guide

the delete will only be allowed if no child records exist. Both methods ensure that child-file
records will never become orphan records.

You may change this property at run time. Note that different data-dictionary structures
may be required for a view that allows cascade_delete and one that does not. The
structure validation that occurs before a delete checks that the data-dictionary structure is
proper for the desired scope of deletion.

Example:
procedure define_fields
forward send define_fields
set main_file to customer.file_number
send add_client_file to orderhea.file_number
set cascade_delete_state to false
:

Setting Field Properties


A field property defines a property for all DEO items addressing a particular field. All field
properties use a similar syntax:

set field_options field_property_name field file.field to value

Where field_property_name is the name of the property (most of these properties actually
start with the field_ prefix), and field is a keyword indicating that the file.field value
following it should be represented as a field number. The use of the field keyword is
important and is discussed in its own section below.

Field_Options
This defines the rules and formatting that should be applied to DEOs that address this
field.

Example:
set field_options field customer.number to dd_noput dd_autofind

The options below shown with an asterisk (*) are finding options, and may be used only
on indexed fields. The other options may be used with any field.

DD_AutoClear
DD_AutoBack
DD_AutoFind*
DD_AutoFind_GE*
-10-
DataFlex 3.2 Data Dictionary Guide

DD_AutoReturn
DD_CapsLock
DD_DisplayOnly
DD_FindReq*
DD_ForcePut
DD_NoEnter
DD_NoPut
DD_Retain
DD_Retain_All
DD_Required
DD_SkipFound
DD_Zero_Suppress

Automatic Find

DD_Autofind executes a find equals on the main index for the field. If the desired find is
on a multi-segment index, the autofind should be on the field that is the last segment of
the index (DD_Autofind uses the main index for that field), so that all data necessary for
finding has been entered. Forms or columns for data from related files will also be filled.
If DD_Autofind is applied to a field whose main index includes the record number, it will
not function.

Automatic Find Greater Than or Equal To

DD_Autofind_ge executes a find Greater than or Equal to on the main index for the field.
If the desired find ge is on a multi-segment index, the DD_Autofind_ge should be on the
field making up the last segment of the index, so that all data necessary for finding has
been entered prior to execution. Forms or columns for data from related files will also be
filled. DD_Autofind_ge will always find a record unless the file is empty.

Skip If Found

DD_Skipfound If the record in the buffer was brought in by a find command, the cursor
will be prevented from entering the form or column attached to this field. In non-mouse
environments, the cursor will skip past the form or column to the first succeeding form or
column that does not have this option. This option is intended to prevent the alteration of
data for selected fields in existing records by not allowing any change, but permitting
access to the field for creation of new records.

Find Required

-11-
DataFlex 3.2 Data Dictionary Guide

DD_Findreq requires that a record retrieved from the database be in the buffer before
users can pass this item in the DEO. It is not supported in Windows, but is supported in
DataFlex for use in environments that do not support the mouse. The cursor will remain in
this window until a successful find is completed. The Previous accelerator key can move
the cursor in reverse to execute the find on another item. Pressing a Clear accelerator
key will return the cursor to the first item on the panel or screen.

Put Data Unconditionally

DD_Forceput puts data in the DEO to the record buffer regardless of whether any data
has been changed from that originally displayed. Normally, unchanged DEO data is not
moved to the record buffer.

Do Not Put Data

DD_Noput prevents data from the DEO from being put into the record buffer. This
protects data on disk that should not be changed by users.

No Data Entry

DD_Noenter prohibits editing of the content of the form or column to which it is applied. In
non-mouse environments, it places the cursor in the next item, skipping the current one,
preventing any entry. DD_Noenter skips the item even if no record is found, unlike
DD_Skipfound (see above).

Display Only

DD_Displayonly is the combination of DD_Noput and DD_Noenter above. In non-


mouse environments, it places the cursor into the next item (skipping the current one),
and prevents putting of data into the record buffer.

Retain Window Display

DD_Retain maintains the data in the DEO even if a clear is executed, but allows the item
to be cleared if two successive clears are keyed.

Retain Window Display Always

DD_Retainall maintains the data in the DEO at all times; it never allows the item to clear.

-12-
DataFlex 3.2 Data Dictionary Guide

Entry Required

DD_Required holds the cursor in the DEO until (some) data has been entered. The
cursor will not advance to the next item on a null Enter.

Go to Previous Window

DD_Autoback moves the cursor to the last position of the previous DEO when left arrow
is pressed from the first position of the item.

Go to Next Window

DD_Autoreturn moves the cursor to the next DEO when the DEO is full.

Clear Window Automatically

DD_Autoclear is not supported in Windows, but is supported in DataFlex for purposes of


non-Windows environments. In such environments, it clears the DEO of existing content
when entry is made to the first character of the item. If right arrow is pressed and entry
then made to positions after the first in the window, this property has no effect. It is to
facilitate replacement of the entire contents of a window when that is desired. Its
behaviors are obviated by the default behaviors of Windows.

Upper Case

DD_Capslock converts all lower-case alphabetic characters in the DEO to upper-case.

Blank Zeroes

DD_Zero_suppress replaces true zero values in Number items with spaces, eliminating
the display of zero and a decimal point that Number items produce without this option. If a
value is not exactly zero but the precision of the window displays a zero value, zero will be
displayed regardless of whether this option is used.

Examples
procedure define_fields
:
set field_options field customer.id to dd_noput dd_autofind dd_capslock
set field_options field customer.balance_due to dd_displayonly

Often multiple options must be set for a single field. You may pass all options within a
single message, you may create individual messages for each option, or you may mix the
two techniques. The following example is equivalent to the above example:
-13-
DataFlex 3.2 Data Dictionary Guide

procedure define_fields
:
set field_options field customer.id to dd_noput
set field_options field customer.id to dd_autofind
set field_options field customer.id to dd_capslock
set field_options field customer.balance_due to dd_displayonly

Two additional messages are supported to allow item options to be cleared:


DD_clear_field_options - clear the item options passed by this message.
DD_clear_all_field_options - clear all item options for this field.

Example:
Procedure Define_Fields
:
// clear the noput item option (if it is set)
Set Field_Options Field Customer.ID to DD_CLEAR_FIELD_OPTIONS DD_NoPut
// clear all item options for this field
Set Field_Options Field Customer.Number to DD_CLEAR_ALL_FIELD_OPTIONS

These messages are rarely used.

Foreign_Field_Options

The entry_item command assigns a data-file and data-field value to the form or column.
This data file will either be the main file of the DEO’s data dictionary, or it will be a parent
file. When used as a parent file, the entry_item is considered to be a connected to a
“foreign field.” It is important to understand the concept of a foreign field. The following
example shows an entry item that is not foreign followed by an entry-item that is foreign:

object ef1 is a dbForm


set server to (orderhea_dd(current_object))
entry_item orderhea.order_number // this is not a foreign field
:

object ef2 is a dbForm


set server to (orderhea_dd(current_object))
entry_item customer.number // this is a foreign field
:

When a file number is not the same as the number of the data dictionary’s main file, the
file is almost always an ancestor (parent, grandparent, etc.) file. If it is not, you have
probably made an error. Ancestor-file entry items are usually used differently from main-
file entry items. When entering a new record for the main file, the parent-file records are
not modified. Their role is to provide field values (customer number, etc.) on which
relations are based from the main file to the ancestor. When the parent file must be

-14-
DataFlex 3.2 Data Dictionary Guide

changed (add, delete, modify) this is done in a different view, in which that file is the
DDO’s main file.

Because of this, foreign fields often require different field-property settings. The
foreign_field_options property allows you to assign additional field properties to be
applied when a field is addressed from views to which its file is foreign.

Although foreign-field options may be assigned to individual fields, there is a more-


convenient way to set these field options. Three special type designators may be used to
assign foreign-field options to all fields of a specified field type. Those types are key fields,
index fields, and non-index (default) fields. The keywords used to designate these field
types are DD_keyfield, DD_indexfield, and DD_default. This is much easier than having
to set foreign-field options for each field in your data file.

Example:
procedure define_fields
:
set field_options field customer.id to DD_noput DD_autofind DD_capslock
set field_options field customer.balance_due to DD_displayonly
:
// define default foreign field options
set foreign_field_options dd_keyfield to DD_findreq
set foreign_field_options dd_indexfield to DD_noput
set foreign_field_options dd_default to DD_displayonly

Foreign-field properties are added to any field properties that may have been applied
directly to the field. In the above example, (non-foreign field) customer.Id’s field options will
be noput, autofind and capslock. Its foreign-field options will be noput, autofind,
capslock and, since it is a key field, findreq.

Key Fields

Key fields are fields which have been designated to uniquely identify records in a
database (customer numbers in a customer file, for example). The property used to
designate key fields is key_field_state. After you have designated key fields, you may set
options for them all with foreign_field_options.

Example:
Procedure define_fields
:
set key_field_state field customer.id to true
:
set foreign_field_options DD_keyfield to DD_findreq

-15-
DataFlex 3.2 Data Dictionary Guide

Key_Field_State

Setting a field’s key_field_state identifies this field as being part of the file’s primary key.
This information is used to protect key fields and to apply foreign-file options to key fields
as a group (type). A data file may have one primary key. This key can consist of multiple
fields. Each key field must have its key_field_state set to true.

Example:
procedure define_fields
:
set field_options field customer.id to dd_noput dd_autofind dd_capslock
set key_field_state field customer.id to true

Protect_key_state

Protect_key_state determines if the fields that make up a primary key should be


“protected” after they have been saved the first time in a new record. When set to true, a
field identified as being part of a key cannot be edited after it has been saved. This
ensures that child records that relate to a parent through a primary key will not become
accidentally orphaned. The fields that make up a primary key are identified by using the
key_field_state field property.

Example:
procedure define_fields
forward send define_fields
set main_file to customer.file_number
send add_client_file to orderhea.file_number
set cascade_delete_state to false
set protect_key_state to true
:

Auto-incrementing

When you wish to assign a unique key, or identifier, from a system file to new records
when they are created, you can use the define_auto_increment command within the
define_fields procedure.

Example:
define_auto_increment ordsys.cust# to customer.number

In this example, Field cust# in System File ordsys is designated to increment and provide a
value to Field number in Main File customer whenever a new record is saved in customer. Only
one field can be made auto-incrementing in a given main file.
-16-
DataFlex 3.2 Data Dictionary Guide

Field Validation Options

A wide range of validation options may be applied to a field. Three of the most-commonly
used types of validations may be defined within a single validation message Those are
check (value entered must match item within the check string), range (value entered
must be within the numeric or date range), and checkbox (value entered must be one of
two values - most often used with checkbox entry items).

You may also define a validationTable. You create a validation-table object and then
assign the object to a field by setting the field_value_table property. This table is used to
contain a list of valid items. A field uses these values for validation (optional) or as a
means of providing a list of suggested values (combo boxes will fill with these values).
Several types of validation tables are provided. A very useful table is the “code” table.
This table gets its values from a single “Code” file. A code file contains records consisting
of a type, a code, and a description. By the specification of a type, the table provides all
valid codes and descriptions for that type.

The field_validate_msg lets you assign a message to be sent when a field should be
validated. This message (usually a function) will get called whenever a validation is
required, and will pass the following data: field number and current field value. If an error
is detected, the function should generate an error and return a non-zero value.

Normally all fields in all files that participate in a save will be validated. This includes fields
that have no visual representation in the current view and this includes all fields in all
ancestor files. In almost all cases, this level of data protection is desired, and is a
powerful feature of the data dictionary. In rare cases, you may wish to select lower levels
of validation protection. The property validate_foreign_file_state determines if field
validation should be applied to foreign (ancestor) files. Normally you want this level of
validation, so its default value is true. Setting its value to false will skip field validation
when the file is used as a parent file in your data-server object structure. It will also
suppress validation in all additional ancestor files. The property
validate_deos_only_state determines if field-level validation should be applied to all
fields or only to visible fields. When reset to true, field validation will only occur on fields
that have a user-interface component. This would make your DataDictionarys behave
more like DataSet objects, where validation is only applied to visible entry items.

Setting these properties away from their defaults essentially defeats full field validation
and potentially compromises data integrity. They should only be used under carefully
controlled circumstances. Why would you wish to set these properties away from their
defaults? When converting applications from data sets to data dictionaries, you may find
that the extra level of field validations is generating errors in existing records. In such a

-17-
DataFlex 3.2 Data Dictionary Guide

case, you may need to disable some validations until these problems can be corrected. In
other cases, you may find that limiting validations results in performance gains.

One final word of warning. Do not use these properties as short-cut solutions to bad
database design. Special conditional validation rules can be programmed directly into
your validation routines. For example, you could build a validation routine that only applies
a field validation to new records (check the record’s status with the current_record
property) or you could create validation routines that selectively skip certain fields when
they are foreign (the operation_origin global integer tells you which DDO started the
save). Rather than breaking a rule, attempt to define this rule change as part of your rule
set. In the long run, you will have a better, more-robust application.

Field_Value_Range

This message is used when valid field values are limited to a range of numbers or dates.
This property is set to a minimum and a maximum value to define the range. If the field
value falls outside this range, an error will be generated. In addition to being used for
validation, these minimum and maximum values may also be used with spin-button entry
items. If a dbSpinForm is assigned to a field using range values, the spinner’s range will
be limited to the range assigned in the data dictionary in this property.

Example:
procedure define_fields
:
set field_value_range field customer.discount to 0 60

When a validation error occurs, the field error number and message specified by the
field_error property will be used to generate an error. If no message was specified, a
standard range-error advice will be generated.

Field_Checkbox_Values

When a valid value is limited to two choices, you should define these values with the
field_checkbox_values property. This defines the two values as a true-value and a
false-value, and defines the field to be a checkbox field. Checkbox fields may be used
with normal entry forms (in which case users must enter one of the two valid values) or
with a checkbox-entry item (in which case a checkbox is created to represent the field’s
state). This makes it very easy to provide checkbox-entry objects in your views. Simply
create the checkbox object and give it a display label. The data dictionary will handle the
conversion of field values to checkbox display states.

Example:

-18-
DataFlex 3.2 Data Dictionary Guide

procedure define_fields
:
set field_checkbox_values field customer.status to “A” “I” // active/inactive

When a validation error occurs, the field error number and message defined by the
field_error property will be used to generate an error. If no message was defined, a
standard checkbox-error advice will be generated.

Field_Value_Check

This message is used when the list of valid field values is limited to a static, small set of
simple values. These samples are identified in a “check” string. This consists of a list of
valid values separated by the | symbol. For example, the choices A, B and C would be
represented by the check string A|B|C. The choices CA, FL, and TX would be
represented by the check string CA|FL|TX. In addition to being used for validation, these
values may also be used with combo-box entry items. If a dbComboForm is assigned to
a field using check values, each value in the check string will be loaded into the combo
list.

Example:
procedure define_fields
:
set field_value_check field customer.region to “N|S|E|W”
set field_value_check field customer.state to “CA|FL|NY|AZ”

The customer.state example above is probably not a good usage of this validation method.
Adding new states to this list requires program changes, and the string may quickly
become too large to be practical. In such a case, you will want to use a validation table to
provide the values.

When a validation error occurs, the error number and text specified for the field in the
field_error property are used to report an error. If no text was defined, a standard check-
error text will be reported.

Field_Value_Table

If a field needs to be validated against one of two values, a limited set of values, or a
range of values, you can use one of the extended validation methods already detailed
(field_checkbox_values, field_value_check and field_value_range). In many cases
you will find that these types of validations are too limited for your needs. In such a case,
you may use the field_value_table validation type.

Using a field-validation table has the following advantages:

-19-
DataFlex 3.2 Data Dictionary Guide

• you can specify a larger number of valid values than can easily fit within a
check string
• you can specify and display a description for each value in your list
• you can dynamically maintain your list of values (i.e., the values do not have
to be coded directly in your program)
• you can make this list optional choices (i.e., you can display a list of
suggested values during data entry but users are not required to make a
selection from the list)

The use of validation tables provides tremendous flexibility. They will be discussed in
greater detail in an upcoming section. For now, we will introduce the primary validation-
table classes:

ValidationTable

This class allows you to maintain a list of valid values.

Example:
Object Status_Table is a ValidationTable
Procedure Fill_List
Send Add_table_value “O”
Send Add_table_value “C”
Send Add_table_value “D”
end_Procedure
End_Object

DescriptionValidationTable

This class allows you to maintain a list of valid values and their associated descriptions.

Example:
Object Status_Table is a DescriptionValidationTable
Set List_Title to “Customer Status”
Procedure Fill_List
Send Add_table_value “O” “Opened”
Send Add_table_value “C” “Closed”
Send Add_table_value “D” “Flagged for Deletion”
end_Procedure
End_Object

FileValidationTable

This class allows you to maintain a list of values and descriptions that can be easily
loaded from a specified DataFlex data file.
-20-
DataFlex 3.2 Data Dictionary Guide

Example:
Object Status_Table is a FileValidationTable
Set Main_File to CustStat.File_Number
End_Object

CodeValidationTable

This class allows you to load your data and description values from the DataFlex Code
List.

Example:
Object Status_Table is a CodeValidationTable
Set Type_Value to “Status”
End_Object

Any of the above validation tables can be linked to a field with the field_value_table
message in a data dictionary.

Example:
Set Field_Value_Table Field Customer.Status to (Status_Table(Current_Object))

Field_Validate_Msg

This lets you assign a general-purpose message to be sent when a field should be
validated. This message (usually a function) will get called whenever your program
requires a validation. This validation method is used when you need to perform complex
validations that can only be expressed with code. Since it is a very open-ended process, it
can do just about anything. If the value is valid, the function should return a zero. If the
value is invalid, the function should generate an error and return a non-zero value.

You must create the validation function(s). This function will get passed the field number
and the current field value. Your function may use these values as it sees fit. For this
purpose, the value of any other field in the data dictionary may be obtained by getting the
field_current_value property. It is important to note that the validation routine should
never need to access a value in a DEO. The information required should be found in the
DDO or in one of the DDOs connected to it.

Example:
procedure define_fields
:
set field_validate_msg field employee.pay_type to get_valid_pay_type

-21-
DataFlex 3.2 Data Dictionary Guide

The special-purpose field-validation methods (field_value_check, field_value_range,


field_checkbox_values and field_value_table) are mutually exclusive. A field_validate
message, however, may be used in addition to any of the special-purpose validation
methods (this will be a rare occurrence).

Field_Error

This allows you to define a custom error number and error message for a field. The
range, check, checkbox, and table validations will display these messages when a
validation fails. You can use these messages inside a custom field_validate_msg
function by sending the field_error message.

Example:
procedure define_fields
:
set field_checkbox_values field customer.status to “A” “I” // active/inactive
set field_error field customer.status to 900 “value must be A or I”

Field_Entry_Msg / Field_Exit_Msg

These messages are similar to the field_validate_msg and are sent whenever the cursor
enters or exits an item connected to a field. You would create the procedures and then
assign the procedure names to the field properties. When called, the procedures are
passed the field number and field value. While returning a non-zero would stop the
navigation event, this would be unusual usage. These procedures are usually used to
handle pre-entry or post-exit processing.

Status_Help

This defines a status-help text line for the field. Entry objects will use this to display
status-bar help.

Example:
procedure define_fields
:
set status_help field cust.status to “A customer is either Active or Inactive”

Field_Prompt_Object / Field_Zoom_Object

These properties assign prompt or zoom objects to fields. The field_prompt_object


allows you to assign a prompt list to a field. This is required when you’ve got relational
-22-
DataFlex 3.2 Data Dictionary Guide

lookup (or any type of lookup needs). If you are using one of the extended validation types
(check, checkbox, or any validation table) the data dictionary is smart enough to be able
to provide a default prompt list. It does this if there is no prompt list explicitly assigned. So
if you assign a field_prompt_object for a field, it will get used in place of the prompt list
provided for extended validations.

Example:
procedure define_fields
:
set field_prompt_object field customer.name to (cust_lkup(current_object))

Setting Defaults
You may set default field properties and values that fields will contain before users enter
data.

Defining Field Defaults

The field_defaults procedure is provided to support the setting of default values after a
clear. You may set any field value, which will then be reflected in the DEOs and will get
saved with the new record. Because the setting of defaults is coded in a procedure, it
allows for complex rules. The setting of a default is not recognized as a data change by
the data dictionary; therefore the setting of defaults will not generate a “data-loss” error
message. Defaults may also be set upon entry of an entry item by setting the
field_entry_msg and field_default_value properties.

Example 1:
Procedure Field_Defaults
Set Field_Changed_Value field customer.state to “CA”
Set Field_Changed_Value field customer.discount to 10
Set Field_Changed_Value field Customer.City to “Miami”
End_Procedure

Example 2:
Set Field_Entry_Msg field ORDERHEA.ORDER_DATE to Entry_Order_Date

Using the Field and File_Field Message Parameters


Before a field can be accessed in a property or message only by its field number in its file.
Several commands make this process simpler. A special command named
get_fieldnumber can be used to extract a field number from a file.field. It has the
following format:

-23-
DataFlex 3.2 Data Dictionary Guide

get_fieldnumber file.field to field_num

It could be used in the following way:


get_fieldnumber customer.name to custname
set field_options item custname to DD_autofind

Because this type of access will be required so frequently in data dictionaries, a special
command parameter has been provided to support this within a single message. When
the keyword field is used, the file.field names following it will be converted to a field
number. The above example could therefore be rewritten as follows:

set field_options field customer.name to DD_autofind

The file_field_ messages require that both a filenumber and a field number get passed.
This could be done as follows:
get_fieldnumber customer.name to custname
set file_field_current_value customer.file_number custname to “John”

A special keyword, file_field, allows you to shorten this as follows:


set file_field_current_value file_field customer.name to “John”

You will rarely need to use the file_field_ messages and therefore you will rarely use the
file_field keyword. Field_ messages are used all the time and the field keyword will be
used extensively. You must remember to use this keyword. If you omit it or use the item
keyword in its place, you will get a very different result.

Making Data-Dictionary Subclasses


An application may consist of several views that need the same data file. For example, a
check-writing view and a vendor-entry view will both need to use the vendor data file.
Each of these views will have a separate DDO based on this file to provide it with the
needed services. Even though these DDOs are based on the same file, they will be
independent of each other. Changes in one view will not affect data in another view.
Proper encapsulation will ensure this. Although these DDOs are independent, they share
a number of common characteristics. The database rules for these objects should be the
same. Any special rules for the data file should be obeyed by all DDOs based on this file.
These rules belong in a subclass specifically for the file. All DDOs for that file should be
based on that subclass.

The Simplest Data-Dictionary Subclass


A DDO’s database file is specified in a property called main_file. If you do nothing else,
your data-dictionary subclass should set this main_file property. This way you will not
-24-
DataFlex 3.2 Data Dictionary Guide

have to identify the file name at the object level. The following example shows how a
DataDictionary subclass would be created for a data file.

If subclass is based on the DataDictionary class

Class Vndr_DataDictionary is a DataDictionary


Procedure define_fields
Forward Send Define_Fields
Set main_file to Vndr.File_Number // identify file #
end_procedure
end_class

If subclass is based on the dataSet class.


Class Vndr_DataDictionary is a DataSet
Procedure construct_object
Forward Send construct_object
Set main_file to Vndr.File_Number // identify file #
end_procedure
end_class

Then your object would be:


Object Vndr_DD is a Vndr_DataDictionary
end_object

You would probably keep the code for your subclass in its own package file (with a .DD
filename extension), using this file from any program that needs to create DDOs based on
this class (that is, that use its files and the same rules for their data). Depending on the
size of your application, you might choose to place each data-dictionary subclass in its
own package file or you might choose to place all of the data-dictionary subclasses in a
single package file. By placing the class in a package file, you can change your data-file
rules by changing a single file and recompiling all programs that use this package file.

The main_file for a data-dictionary subclass is the database file that this subclass is
meant to control. When the save, delete, clear, and find operations are performed for
this DDO, the record in the main file is the record affected. This is critical when using
multiple DDOs: the DDO that is the server for a DEO determines the actions of the Save
Record (F2), Delete Record (Shift+F2), and Clear (F5) keys. When these keys are
pressed in a DEO, a message is sent to that DEO's DDO to perform the action. The
save, delete, or clear is executed for the main file of the DDO that receives the request.
This will be discussed in detail later in this section.

The Data-Dictionary-Operation Messages

-25-
DataFlex 3.2 Data Dictionary Guide

Few data-dictionary subclasses remain as simple as the above example. The


DataDictionary class supports a number of messages that let you control many of the
behaviors of a save, delete, find, and clear. We refer to these as hook messages. Before
we discuss how you use the hook messages in your data-dictionary subclasses, we need
to discuss the major data-dictionary operations.
The primary function of data dictionaries is to save, delete, clear, and find records.
Although these functions always originate with a single request to a single DDO, these
requests propagate over the entire data-dictionary structure (all DDOs that are connected
by set ddo_server and all DEOs that are connected to any of these DDOs by set
server). It is best to think of a data-dictionary operation in terms of the entire data-
dictionary structure and not just a single DDO.

The primary data-dictionary-operation messages and their functions are described here
briefly. These messages are public, which means that they are appropriate messages to
send to a DDO and they are appropriate candidates for augmentation. In actual practice,
you will find that you rarely explicitly send these messages. The DEOs will do that for you
through their class definitions. Also, you will find that you rarely augment these messages.
The data-dictionary hook messages, on the other hand, are often augmented.

The Clear and Clear_all Messages


These messages are responsible for clearing data-dictionary structures. The clear
message clears some DDOs in a structure, while the clear_all message clears all DDOs
in a structure. See the section on “Propagation of Data-Dictionary Operations” on Page 56
to determine what DDOs are cleared. After a clear, all participating DEOs are refreshed.

The Find Messages


There are a number of find messages supported by DDOs. The primary messages are
request_find, request_superfind, and find_by_recnum. The purpose of these
messages is to move data from the DEOs to the file buffer, perform the appropriate find
operation, and to update the DEOs with values from the newly found records. A find
operation in one DDO will affect other DDOs in a structure. Parent records are related
and child records are at times found. All DDOs and DEOs are notified as required.

The Request_save Message


When the save operation is performed by a DDO, it saves records into its main file as
well as the files in its updated DDOs. This allows updates in total fields in related files to
be performed as each record in the main_file is created or edited. This action can also
cause the creation of new records in any of the files. Any record buffer that was not
pointing to an already-existing record will have a new record created. As an example,
when entering a new order record, it may also be desirable to add the (new) customer for

-26-
DataFlex 3.2 Data Dictionary Guide

that order at the same time. Because you listed the customer file as one of the updated
DDOs, the new customer record can be created automatically when the order (the main file)
is saved.

The request_save message is responsible for saving new or existing records. A


request_save will:

1. Lock required data files.


2. Reread and backout (and save if required) all original data.
3. Move all changed data from the DEOs to the file buffer.
4. Send creating to all DDOs with new records.
5. Send update to all participating DDOs.
6. Get validate_save of all participating DDOs. If any validate_save fails,
cancel the operation.
7. If all DDOs validate, attach, and save all records (attach_main_file,
save_main_file).
8. Unlock data files.
9. Refresh all participating DEOs.

If validate_save fails or any error is generated, the save is rolled back and the data files
and DDOs are restored to their original contents.

The Transaction_aborted message

The message transaction_aborted is sent when a save is canceled by validate_save. If


the save was canceled by validate_save returning a non-zero number, that return value
will be passed to transaction_aborted. If the save was cancelled by validate_save
generating an error message, the value passed to transaction_aborted will be zero. In
this case,

you can query the last_err integer to see what error was generated.
Transaction_aborted is sent after the transaction has been rolled back, the data files
have been unlocked, and the error message (if any) has been displayed. With the addition
of automatic transaction rollback in DataFlex, the need for the transaction_aborted
message has lessened. It remains in the product for compatibility reasons.

The Request_validate Message


Before a data-entry object sends the request_save message to its DDO, it sends the
message request_validate. Request_validate sends the message validate_items to all
DEOs that will participate in the upcoming save. If the validation of any item fails, an error
is reported and the save will not proceed. You will probably never send or augment this
message.
-27-
DataFlex 3.2 Data Dictionary Guide

It is important that you understand that this process occurs. Before a save, every single
item in every single DEO that will participate in the save will be validated. This is a pre-
save validation. Your database is not locked at this point. This item validation is a different
process than the actual DDO save validation (validate_save), which occurs much later in
the save process.

The Request_delete Message


The request_delete message is responsible for deleting a record in the DDO for the
main file, updating all parent DDOs (and files) and possibly deleting all child records. Two
modes of deleting are supported. A delete will either delete all related descendant
records, or it will disallow the delete when child records exist. The property
cascade_delete_state controls this (see “Validate_delete_no_cascade and
Cascade_delete_state” on Page 33).

Deleting a record and all of its children

If cascade_delete_state is true, request_delete will attempt to delete the DDO’s record


and all descendant records. In order for this to work, the following two conditions must be
met: 1) All DDOs for descendant files must be properly connected to the data-server
structure (with set ddo_server); and 2) there must be a valid relationship between the
child and the parent files defined in the file definitions (or with a set_relate command).
When this condition is met, the following will occur:

Deletes when cascade_delete_state is true:

1. Lock required data files.


2. Reread all required records.
3. Get validate_delete of the main DDO.
if validate_delete fails, cancel the operation
4. Delete all related descendant records.
for each child record:
Send deleting to the main DDO.
Send backout to all parent DDOs.
Save all parent files
5. Send deleting to the main DDO.
6. Send backout to all parent DDOs.
7. Delete the main record (delete_main_file)
8. Save all parent files
9. Unlock data files.
10. Refresh all participating DEOs.

-28-
DataFlex 3.2 Data Dictionary Guide

Preventing Deletes When Child-File Records Relate to the Record

If cascade_delete_state is false, request_delete will not allow users to delete a record


when a child-file record(s) exists. For this process to work, you must list all child (client)
files in the data-dictionary subclass. This is done by sending the message send
add_client_file filename.file_number for each child file. It does not matter if these child
files are connected to the data-dictionary structure.

However, these files must be open (or the delete will not be permitted) and there must be
a valid relationship between the child and the parent files defined in the file definition (or
with a set_relate command). When these conditions are met, the following will occur:

Deletes when cascade_delete_state is false:

1. Lock required data files.


2. Reread all required records.
3. Get validate_delete of the main DDO.
4. Check for any child records or closed files (get
validate_delete_no_cascade)
if either validation fails, cancel operation
5. Send deleting to the main DDO.
6. Send backout to all parent DDOs.
7. Delete the main record (delete_main_file)
8. Save all parent files
9. Unlock data files.
10. Refresh all participating DEOs.

Rolling Back a Transaction


If a save or a delete operation fails for any reason, the entire save or delete operation (the
transaction) is rolled back and your data files and DDOs are restored to their original pre-
save or pre-delete condition. Normally an operation will be stopped by a failure in
validate_save or validate_delete. However, a rollback will also occur any time an error
is encountered during the locked process. This error can be developer-generated (with
the error command) or runtime-generated (e.g., a duplicate-index-value error).

Errors in Data Dictionaries


If an error occurs in a DDO during a locked process, two things happen: 1) the DDO
process is stopped and the transaction is rolled back; and 2) the error message is not
actually generated until after the rollback and the data files are all unlocked. The deferral
of the error message ensures that the error will not be reported while data files are
locked. When an error occurs, all processing of code stops. The remainder of the DDO

-29-
DataFlex 3.2 Data Dictionary Guide

messages are not sent and the remainder of any procedure or function code is not
executed. In the following example, the code following the error command in
validate_save will never get executed:

function validate_save returns integer


error 300 "We have an error"
// these two statements will never get executed.
send bell
function_return 1
end_function

If you generate an error inside validate_save or validate_delete, there is no need to


return a non-zero value. The process has already been halted.

Smart File Locking


You will notice that the first step in the save and delete operations is to lock the required
files. Normally a lock or reread implies that all open data files will be locked. DDOs
support a file-locking scheme that only locks and rereads the actual files that will
participate in the save or delete operation. This can result in significant speed benefits.
Smart filemode is an automatic feature of the data-dictionary class. In data-dictionary
subclasses, smart filemode must be enabled by setting the property
smart_filemode_state to true in all DDOs participating in the save or delete operation.
Normally, this would be set in your data-dictionary subclass. An additional procedure
named reset_filemodes_for_lock may be augmented to handle any special locking
conditions (like the locking of a system file). This important topic is discussed in detail
later in this section.

Read_only_state
Many applications use a file for lookup only. In these situations, the DDO’s
read_only_state may be set to true and no save operations can be initiated in that DDO.
However, if a save operation is initiated in a client DDO, the server DDO will save, even if
its read_only_state is set to true. This ensures database integrity.

Using the “Hook” Messages

“Hook” messages are so called because they are designed solely to execute any special
functionality you may need to program into saves or deletes. They are “hooks” onto which
you can “hang” procedures of your own definition. You merely need to give your
procedures the special name of the hook you wish to use. DataFlex sends them
automatically at certain points during every save or delete. By default, they do nothing.
You may define these procedures and use them to provide further validation and to
maintain calculated field balances. It is expected that you will use these messages in your

-30-
DataFlex 3.2 Data Dictionary Guide

subclasses. These messages are documented in the DataFlex Class Reference. The
most-common hook procedures and functions are:

Validate_Save
This is used as final validation of a record before saving it. It is called when the database
is locked and all field values have been updated. You may directly query the value of any
file.field buffer and if any value or combination of values is invalid, stop the save by
declaring an error and returning a non-zero value. This should not be confused with field
validation. Field validation occurs before the database is locked and before the fields are
updated to the file buffer. Field validation can be used to handle most validations.
Validate_save is used to handle special validations that can only be checked in a locked
and updated state.

Validate_delete
This is used to validate that a record deletion may be performed. Declaring an error or
returning a non-zero value will stop the process.

Update / Backout / Creating / Deleting


These are used to maintain calculated balances. They are used to calculate running totals
(update and backout) and to assign system IDs to new records (creating).

Propagation of Hook Messages


Unless otherwise noted, the messages listed are sent to all the objects in a data-server
structure that will participate in a particular operation. Validate_save, for example, gets
called during a save operation. A save involves the DDO that actually started the save
(received the request_save message) and all the DDOs that it updates (saves propagate
up). During a save, validate_save is sent to every one of these objects. When you think
of DDO behaviors, try to think in terms of the behaviors of data-dictionary structures and
not single DDOs.

When a message is propagated through a data-dictionary structure, the order in which


messages are sent will vary. In some cases, a message will be sent to the parent-most
(server) DDO and propagate down to the child DDOs (clients). The save_main_file
message propagates in this manner. Other messages will start with the child and
propagate up to the parents. The update messages propagate in this manner. Usually all
you need to know is that the message will get sent to the right DDOs in the right order
based on the function of the message.

-31-
DataFlex 3.2 Data Dictionary Guide

Forward-Sending Hook Messages


Many of the data-dictionary hook messages perform no default action. They are provided
so that you can build your own custom rules. When you augment one of these hook
messages, it would seem unnecessary to forward-send the message; the behavior of the
forwarded message would be to do nothing at all. Although you do not have to forward
send such messages, you should nonetheless. It is good object-oriented programming
practice to always forward a message unless you explicitly wish to cancel the forwarded
behavior. All of our examples will forward messages (unless we wish to cancel a
behavior). So, while we could code a procedure as follows:

procedure update
add order.total to customer.due
end_procedure

We will instead code this with a forward send:


procedure update
forward send update
add order.total to customer.due
end_procedure

The Validation Hook Messages


Validate_Save Function

The validate_save function is called right before a record is about to be saved. If a DDO
is connected to other DDOs, the validate_save message will be sent to all DDOs that will
participate in this save. If any of these calls returns a non-zero value, if an error is
generated, or the message operation_not_allowed is sent (which generates an error),
the save will not occur. At the point that these functions are called, all of the data has
been moved into all of the buffers. The data in the file buffer is exactly what would get
saved. The exception to this is that the file attaches have not yet occurred. This means
that a child-file buffer may not contain the parent information that will get placed in the file
with an attach. The attach occurs after the validate_save.

The data files of all participating DDOs are locked during validate_save. Therefore, the
function should be fast and must never call for user input. The exception to this is the
error command. An error generated during the validate_save will be deferred until after
the save has been reversed and the data files have been unlocked. This only occurs with
errors generated with the error command. Typically, a failed validate_save will generate
an error message, as in the two examples below.

Function validate_save returns Integer


local integer rval
If Invt.Qty lt 0 ;
Error 301 'Insufficient Inventory on hand'
-32-
DataFlex 3.2 Data Dictionary Guide

forward get validate_save to rval


function_return rval
end_function
Function validate_save returns Integer
local integer rval
If Invt.Qty lt 0 ;
send operation_not_allowed 301
forward get validate_save to rval
function_return rval
end_function

Because the buffers for all participating files have been updated, you should not find,
clear, delete, or alter these file buffers.

Validate_delete Function

This function is called right before a delete will occur. The participating files are locked.
Returning a non-zero value, generating an error, or sending the message
operation_not_allowed (which generates an error) will stop the delete.

A delete operation will delete the main file and all related descendant-file records (child,
grandchild, etc.). It does this to prevent orphans. This only occurs if
cascade_delete_state is true and there is a child-parent relationship between the files
and there exists a set ddo_server relationship between the files’ DDOs. Constraints have
nothing to do with this.
The validate_delete is only sent to the DDO in whose main file the delete is being done.
If validate_delete is approved, the main-file record and all child-file records will be
deleted.

If you are prohibiting cascade deletes, it is vital that you forward the validate_delete
message. The cascade-delete checking occurs as part of this forwarded behavior:

Function validate_delete returns integer


local integer rval
forward get validate_delete to rval
if rval ne 0 function_return rval
If customer.Status eq 'A' ;
send operation_not_allowed 306
end_function

Validate_delete_no_cascade and Cascade_delete_state

You may not want to delete records that have child records (while allowing those lacking
children to be deleted). It often does not make sense to allow users to delete this kind of
history. In addition, the entire delete operation takes place in a single locked state. If you

-33-
DataFlex 3.2 Data Dictionary Guide

are deleting a record with a lot of descendant records, you may be locking other users out
of the database for an unacceptable period of time.

This can be controlled with the cascade_delete_state property and the add_client_file
message. When a DDO’s cascade_delete_state is false, it will not allow deletion of
records for which a child file named in an add_client_file message holds records that
relate to the record to be deleted. Any relating records in files not named in an
add_client_file message will not prevent the delete (and will be themselves deleted).

The following example subclass will disallow deletes if a related record is found in either
child file (or if either child file is not open). Note that it is not required that DDOs exist for
the child files; cascade-delete checking checks files directly, not through DDOs:
class customer_data_dictionary is a DataDictionary
procedure construct_object
forward send construct_object
set main_file to customer.file_number
set cascade_delete_state to false // no delete if children
send add_client_file orderhea.file_number // child file 1
send add_client_file calbacks.file_number // child file 2
end_procedure // construct_object
:
end_class

Validate_delete sends the validate_delete_no_cascade message to make the


foregoing happen. If you provide your own custom validate_delete definition, this
definition must contain a forward get validate_delete to rVal statement in order to keep
this function working.

If you need to check for child records in a non-standard manner, you could augment
validate_delete_no_cascade to perform this task. When a cascade delete fails, the error
is reported by sending the message operation_not_allowed. One of two error numbers
is passed to this procedure: 4139 Cannot delete - related files not open, and 4140
Cannot delete - related records exist.

Even if you do not intend to use cascade-delete prevention, you are strongly encouraged
to list all required client files in your subclass with the add_client_file message. Future
versions of data dictionaries will be able to take further advantage of this information, and
may require it.

Operation_not_allowed

This message is sent whenever a DDO receives a message to perform an illegal or


impossible operation. The message is sent with one parameter, an error number. This
can be the number of an error defined in your program, or the number of any predefined
-34-
DataFlex 3.2 Data Dictionary Guide

DataFlex error. This message centralizes the error handling for errors generated in
DDOs, but only those errors. It does not handle errors generated by the database
manager or user-defined code that does not send operation_not_allowed.

Operation_not_allowed can be augmented to send customized error messages. For


example, we may have decided to alter one of the existing error messages (4140 Can't
delete - child records exist) and add two custom messages (301 Insufficient Inventory
on hand, and 303 Can't delete active customer). This assumes that validate_save and
validate_delete are sending operation_not_allowed and passing the appropriate error
numbers:

procedure operation_not_allowed integer err#


if err# eq 301 error err# "Insufficient Inventory on hand."
else if err# eq 303 error err# "Can't delete active customer."
else if err# eq 4140 error err# "- Customer has orders assigned."
else forward send operation_not_allowed err#
end_procedure

The Database-Updating Messages


The messages update, backout, deleting, and creating allow you to assign and
maintain balances during a save or delete operation. These might be counters, record
IDs, or relational balances. All of these messages have certain features in common.

• You should make sure that all files referenced in these procedures are
represented the DDO structure and that the DDOs are properly
interconnected with set ddo_server.
• You should not attempt to stop a save or delete inside of one of these
procedures. Do not return a non-zero value and do not generate an error
message in these procedures.
• These messages get sent to all DDOs that participate in the save or delete.
The order in which these messages are sent to the DDOs varies depending
on the process. Don't worry about the order; DDOs do this correctly.
• These messages are sent when the participating database files are locked
and their buffers contain the correct information.

Update, Backout Procedures

These messages are used to maintain relational balances between data files. Update is
called when a record is being saved or edited. Backout is called when a record is being
edited or deleted. Update and Backout will usually adjust the balances of parent files.
The following update and backout in a checks DDO would adjust the balances of its
parent, the vndr data file.

-35-
DataFlex 3.2 Data Dictionary Guide

Procedure Update
Add Checks.Total to Vndr.Total_Paid
end_procedure
Procedure Backout
Subtract Checks.Total from Vndr.Total_Paid
end_procedure

When a new record is saved, update (and not backout) is called. When a record is
deleted, backout (and not update) is called. When a record is edited, backout and
update are both called. It is possible that the backout and update might adjust different
parent balances during an edit. This would happen if the edit caused the parent record to
change. DDOs support this.

The contents of an update and backout will almost always be the inverse of each other.
Whatever update adds to a balance, backout should deduct. Do not make the
assumption that update and backout only get sent once during a save. While this is true
in cases where parent records are not switched, it will not be true when parent records
are switched. The process of maintaining relational integrity when parent records are
switched is quite complicated and both procedures can be called multiple times for the
same data file (for different records).

If a change in a record should adjust balances in both a parent and a grandparent record
(e.g., check detail adjusts checks total, which adjusts vendor total), it is best to let a file only
adjust its immediate parents (e.g., check detail's update would adjust the checks file, checks's
update would adjust the vendor file).

Deleting

Deleting is called during the delete process. It gets sent before the backout message.

Creating

Creating is called when a new record is being saved. This procedure is internally
augmented by the define_auto_increment command to assign unique identifier keys
(such as customer numbers) when new records are created.

Other Messages
The most-commonly augmented message handlers have been listed. Those are
validate_save, validate_delete, update, backout, deleting, and creating. The following
messages are available for more-advanced data-dictionary control. Unlike some of the
above messages, most of these messages do perform a default function. For that reason,
if you augment these procedures, you must make sure that you forward-send the
message so as to retain the default function.
-36-
DataFlex 3.2 Data Dictionary Guide

Relate_main_file

Relate_main_file does nothing by default. It is called after the normal relate has been
executed. It is a "hook" that allows you to perform custom relates after your main record
has been found and related. If you are going to find an additional record in
relate_main_file, you must notify the DDO that you have found this new record. You do
this by sending the request_relate message (if the record was found) or
request_clear_file (if the record was not found). Request_relate will also perform a
relate on the newly found record.

This is particularly true if the DDO is updating the parent-file DDO of the record you have
found. The following code finds a "soft" parent record and notifies a DDO of the find.
Procedure relate_main_file
forward send relate_main_file
local integer mustFind
if not status softFile move 1 to mustFind
else if vndr.soft_id ne softFile.soft_id move 1 to mustFind
if mustFind begin //relate softFile only if required
Clear SoftFile
Move Vndr.Soft_ID to SoftFile.Soft_Id
Find eq SoftFile.Soft_Id
end
If status softfile Send request_relate SoftFile.File_Number
else Send request_clear_file SoftFile.File_Number
end_procedure

Note the "optimization" of this procedure. The find in softFile is performed only if: (a) the
softFile record buffer is empty; or (b) the record in the buffer is the wrong one (relating
values do not match).

Important: You are strongly encouraged to optimize your finds inside relate_main_file.
Because DDOs have no way of knowing what this procedure is doing, they have no way
of optimizing these finds. Any time a DDO thinks that the custom-related record may be
incorrect, it will send relate_main_file. It gets sent very often. If you do not optimize your
finds (a simple process), you may be significantly slowing down your database operations.

Be aware that relate_main_file is not always finding the record that relates to the current
record. When parent records are switched, relate_main_file will be called during the
save process to find a related record(s) for the switched-from and switched-to records.
Because of this, current_record should not be used in relate_main_file procedures.
There, only the recnum should be used. New_current_record enables you to track
changes to current_record.

-37-
DataFlex 3.2 Data Dictionary Guide

New_current_record

This procedure can be thought of as a post-find procedure since it gets called after every
record find (whenever current_record changes). New_current_record is passed two
Integer parameters: the old record number and the new record number. By looking at
these two parameters, you can tell if the DDO has found a record or if it is creating a new
one (new_recnum is zero). You cannot use this procedure to change current_record.
This message is sent to notify of a change that is going to happen. You cannot abort the
change.

Probably the most-common use of new_current_record is to store the condition of a


data file right after a find. Current_record is a very useful DDO property. If its value is
zero, the record is new. If it is non-zero, the record is old.

New_current_record is sent when the current record is changing, with two exceptions. If
a DDO becomes in-use and the record being established is zero, new_current_record
will be called (old record =0, new record =0). After a save, new_current_record is called
for all DDOs that participated in the save, even if the record did not change. If you need to
test for this condition, you could check operation_mode and see if it is mode_saving.

procedure new_current_record integer oldrec# integer newrec#


forward send new_current_record oldrec# newrec#
// Assume we want to trap saves of existing records.
if (operation_mode =mode_saving AND oldrec# =newrec#) begin
:
end
else ...
end_procedure

Attach_main_file

Attach_main_file performs an attach. It gets called during save and find operations.
You can use this procedure to create additional attaches, to cancel all attaches, or to
create your own custom attaches. The following sample performs a normal attach except
that one of the field's attaches is ignored.

Procedure attach_main_file
Local String TempVal
Move Vndr.Parent_Stat to TempVal // remember this value
// the normal attach will attach data from all parent files
// including an attach into Vndr.Parent_Stat. We want to
// ignore this attach
Forward send attach_main_file
Move TempVal to Vndr.Parent_State // undo this one attach
end_procedure

-38-
DataFlex 3.2 Data Dictionary Guide

Note that attach_main_file and relate_main_file are not true inverses of each other.
Relate_main_file does nothing by default (the relate occurs as part of the find).
Attach_main_file actually performs the attach command.

Save_main_file, Clear_main_file, Delete_main_file

By default, these messages save, clear, or delete the main file. Normally, you will first
want to forward-send this message. You could then save, delete, or clear custom files. If
you are clearing an additional file, you should tell the DDO about this by sending the
message request_clear_file:

Procedure Clear_Main_File
Forward Send clear_main_file
Clear AuxFile
Send request_clear_file AuxFile.File_Number
end_procedure

You can use save_main_file to create time/date stamps in a file. We want a record to be
stamped as changed if there were any changes made in the file. For this reason, we will
augment the procedure that is closest to the actual save. If the file buffer is changed, we
will stamp the record.

Procedure save_main_file
// only stamp the record if it is already changed. This assumes
// that the functions Crnt_Date and Crnt_Time already exist.
IfChange Vndr Begin // if record is changed at all
Get Crnt_Date to Vndr.Date_Stamp
Get Crnt_Time to Vndr.Time_Stamp
End
// now do the normal save behavior.
Forward Send save_main_file
end_procedure

Creating Validate, Entry, and Exit Procedures and Functions

You can specify a procedure or function to be called whenever the cursor enters or exits
any form or column attached to a particular field, or to be called whenever validation on
such an item is triggered. These work the same as the iEntry=, iExit=, and iValidate=
options applied to entry_item commands in DEOs, but in DataDictionarys, they apply to
all items attached to the field via the data dictionary.

You specify the name of the entry message by setting the field_entry_msg property for
each field, the name of the exit message by setting the field_exit_msg, and the validation
procedure by field_validate_msg. You should set these properties in the DataDictionary

-39-
DataFlex 3.2 Data Dictionary Guide

subclass in the define_fields procedure. You should also define the procedures or
functions identified in these properties in the subclass.

These messages can be procedures or, if functions, you should code them to return a
value of 0 when conditions are satisfactory to allow the entry, exit, or other event
triggering validation to complete. You should code them to return a non-zero value for
those situations in which you wish the event to be disallowed, and presumably some error
message or the like. This technique is especially common in the case of validation
messages.

The field_validate_msg is the general case of validation in DataFlex, and has no


definition other than what you code for it. Other, more-specific validations, discussed
elsewhere in this chapter, are supplied in DataFlex with generalized definitions. These are
the field_value_check, field_value_range, and field_value_table properties.
Field_check_values also has some validation functions, which can obviate the need for
a field_validate_msg.

The special-purpose validations just mentioned are accompanied by predefined error


texts that explain the nature of input errors to users upon validation failures, complete with
the parameters for valid entries. If you use a custom field_validate_msg of your own
devising, you may wish to provide error advices by use of the field_error property. This
property, along with those for special-purpose validations, should be set in the
define_fields procedure in your DataDictionary subclass.

Using Validation Tables

If a field needs to be validated as either of two values (Yes/No, etc.), a limited set of
values, or a range of values, you can use one of the extended validation methods already
detailed (field_checkbox_values, field_value_check and field_value_range). In many
cases you will find that these types of validations are too limited for your needs. In such a
case you may use the field_value_table validation type. Using a field validation table has
the following advantages: you can specify a larger number of valid values than can easily
fit within a check string; you can specify and display a description for each value in your
list; you can dynamically maintain your list of values (i.e., the values do not have to be
coded in your program), and you can choose to make this list optional choices (i.e., you
can display a list of suggested values during data entry, but you are not required to make
a selection from the list).

The concept of a validation table is simple. In your program you must create a validation-
table object. This object is then assigned to a field(s) in a data dictionary(ies) by using the
field_value_table message. Once assigned, the field will use this object as a validation
and display resource.
-40-
DataFlex 3.2 Data Dictionary Guide

While the concept and usage of validation tables is simple, their benefits are
considerable. Because the validation and display is handled by special objects, it is
possible to handle just about any type of list-validation condition. In fact, you could create
your own custom validation-table subclasses. It is simply an object containing a list of
valid values (and optionally descriptions) that understands a pre-defined message
protocol so that data-dictionary and data-entry objects may communicate with it.

While you could create your own custom validation subclasses, you will probably not need
to. We have provided a series of validation table classes that will probably handle all your
needs.

Creating a ValidationTable Object


A series of simple examples should provide you with the information required to create
your own validation table objects. We will start this example by not using a validation table
at all. Assume we have a data-entry object defined in one of the following ways:

In Windows
Object Status_Entry is a dbForm
entry_item Customer.Status
End_Object

or
Object Status_entry is a dbComboForm
entry_item Customer.Status
end_Object

In Character-Mode Environments
Object Status_Entry is a Entry_form customer_status_img
Entry_Item
:
entry_item Customer.Status
End_item_List
End_Object

or
Object Status_entry is a Radio_Entry_Form customer_status_img
entry_item Customer.Status
end_Object

We will not change any of these data-entry objects. We will change the validation types
used by the Field Customer.status in the data dictionary. We will start by not using a
validation table at all. Instead, we will assign Customer.Status the following check string:
Set Field_Value_Check field Customer.Status to “O|C|D” // Open, Closed, flagged for Deletion
-41-
DataFlex 3.2 Data Dictionary Guide

By assigning this field, we will get two behaviors:

1. Before saving this record, the value of Customer.Status must be O, C, or D.


2. If a user requests a list of valid values, the choices O, C and D will be
presented. The data-entry class used will determine the type of list that will be
presented. If the DEO is a simple entry form, (entry_form or dbForm), a
popup list will appear when a user selects a prompt. If the DEO is a combo
form (dbComboForm), the drop-down combo list will contain the valid
values. If the DEO is a radio form (radio_entry_form), the choices will be
presented as a radio list. Each of these DEOs knows how to interact with the
data dictionary in a manner appropriate to its capabilities. This entire process
is automatic.

We will now replace the field_value_check message with a field_value_table message.


Set Field_Value_Table field Customer.Status to (Status_Table(current_object))

This is not enough to run (or even to compile). We must now create an object that can be
used by this field. We will do this by creating the global ValidationTable object status_table
above the class that uses it as follows:

Object Status_Table is a ValidationTable


Procedure Fill_List
Send Add_table_value “O”
Send Add_table_value “C”
Send Add_table_value “D”
end_Procedure
End_Object
:
Class Customer_DataDictionary is a DataDictionary
procedure define_fields
:
Set Field_Value_Table field Customer.Status to (Status_Table(current_object))
:

This provides the exact same functionality as field_value_check. Currently, the only
advantage of using a validation table is that this object could be used by other data-
dictionary views that also needed access to the same validation types.

In addition, by changing several properties, we can provide some additional validation


capabilities. Those properties are allow_blank_state, validate_state, and list_title.

If allow_blank_state is true, an empty value (“”) is also considered to be a valid value.


This would now allow the field value to be O, C, D or nothing (presumably undefined). If
you were using a radio_entry_form, you would probably want to set the form’s
-42-
DataFlex 3.2 Data Dictionary Guide

select_mode to single_select. This would allow you to select one of the three values or
nothing.

If validate_state is set to false, validation will not be performed on this field. Why would
you want this? There are times when you want to provide the user with a set of suggested
but not mandatory choices. By setting validate_state to false, you still get access to the
lists (popup lists, combo lists and radio lists) but the values in the lists are not required.
They are suggestions.
Setting a list_title provides a custom title to be used when a popup prompt list is
generated for this list.

The other advantage of using the validation object is that you may fill your list in a variety
of ways. For example, you could load your choices for the following object with a serial list
of line-delimited options.

Object Status_Table is a ValidationTable


Set Validate_State to False // Suggested not required
Set List_Title to “Customer Status” // title for popup prompt list
Procedure Fill_List
Local String stat
Direct_Input “Status.txt”
If not (SeqEof) Begin
Readln stat // read first line
While not (Seqeof)
Send Add_table_value Stat
Readln Stat // read in a status value
Loop
Close_Input
End
end_Procedure
End_Object

Creating a Description ValidationTable Object


By basing our validation table on the supplied ValidationTable subclass of
DescriptionValidationTable, we can provide a description for each item.

Object Status_Table is a DescriptionValidationTable


Set List_Title to “Customer Status”
Procedure Fill_List
Send Add_table_value “O” “Opened”
Send Add_table_value “C” “Closed”
Send Add_table_value “D” “Flagged for Deletion”
end_Procedure
End_Object

The validation process and the data that is read and written to your database will remain
unchanged. Your DEOs will handle this table a little bit differently. Depending on the class
-43-
DataFlex 3.2 Data Dictionary Guide

of the DEO, the data will be presented in data form, description form, or as a combination
of data and description. Your entry forms and grids (Entry_form, Grid, dbForm and
dbGrid) will always display the actual data values. A prompt list will present the
description in addition when invoked from the DEO. Combo forms (dbComboForm) and
radio entry objects (Radio_entry_form) will display just the description. With prompt lists,
combos and radios, you can actually choose to display any combination of data and
description (you simply change a property in the entry object). However, you should find
that the description-only model is the most-widely used method across applications.

In character-mode entry forms (Entry_form) and all grids (Grid and dbGrid), it is
possible to display the description next to the data value. This will be described in a
following section. You will note that the description export feature is not supported in the
Windows entry form. In Windows, the combo form provides a better method of attaining
this functionality.

Using a Database File to Provide Validation Values


The FileValidationTable class (a subclass of DescriptionValidationTable) makes it
easy to load your data and descriptions from a DataFlex file. You do this by setting
properties to define the datafile; the fields for the data value (the code) and the
description, and the index used to load the records. The following example will create a
validation table which will load its data from a file named CustStat whose first field contains
the data value and the second field contains the description. It will load all records using
Index Number 1 of custStat.

Object Status_Table is a FileValidationTable


Set Main_File to CustStat.File_Number
Set Code_Field to 1 // code is in field 1
Set Description_field to 2 // description is in field 2
Set Ordering to 1 // load by index 1
End_Object

Actually, the default values for code_field, description_field and ordering default to the
above values, so this object could actually be defined as follows:
Object Status_Table is a FileValidationTable
Set Main_File to CustStat.File_Number
End_Object

A validation table is a batch-based table. All items are loaded at one time. Therefore, it is
expected that the list of items in any validation table will be (reasonably) short and will be
static (once the table is loaded, the contents of the list will not change) throughout any
session in which it is used. If you have many items or your item list is dynamic, you need
an actual DataFlex file relationship between these files and to use relational validation and
lookup techniques.

-44-
DataFlex 3.2 Data Dictionary Guide

If your list of valid items remains small but may change during usage sessions, you can
create a non-static validation table by setting the static_state property to false. When you
do this, the table is always refilled before it is used for validation and the display list(s)
(combo list, prompt list) is refilled each time it is displayed. Creating a non-static table will
slow down processing because the validation table will be constantly refilling. If the
number of items is small enough, this slowdown will not matter.

Additional properties named type_field and type_value can be used to load a subset of
records from a data file. When these are used, only records whose value in Field
type_field matches the value of type_value will be loaded. When you constrain the
records thus, make sure that your ordering index is optimized to ensure fast loading
(index should be made up of type_field + code_field). You will probably never need to
use these properties because the subclass, CodeValidationTable, provides the means
and the file to accomplish this directly.

Using a Centralized Database File for All Validations


If you use a CodeValidationTable object, your validation values will be loaded from the
CODEMAST file. This file contains sets (or types) of validation values. By specifying the
type, all codes and descriptions for that type are made available, and no others. The data
in this file can be maintained by using the Code Maintenance view.

Object Status_Table is a CodeValidationTable


Set Type_Value to “Status”
End_Object

The following code table will define a non-static table for all Status types. The display
objects will be titled Customer Status Types, and the list will not be used for validation.
Object Status_Table is a CodeValidationTable
Set Type_Value to “Status”
Set List_title to “Customer Status Types”
Set Static_State to False
Set Validate_State to False
End_Object

It is important to note that the DEOs (entry forms, combo forms, radio lists) require no
changes to support any of the above validation tables. These DEOs simply ask for data
and request validation services from their data dictionary. They don’t “care” how this
information is obtained. This makes validation tables extremely flexible and powerful.

Exporting Descriptions from a Validation Table


If you wish, you may create entry forms and grids which allow you to enter a value (or
code) in one item and display the code’s description as displayonly in the following item.
This is supported in multi-item data-entry objects (character mode: Entry_form, Grid,
Windows: dbGrid). It is not supported in Windows dbForms because these are single-
-45-
DataFlex 3.2 Data Dictionary Guide

item objects and it is better supported in dbComboForms. This technique can be used
with any validation table that supports both code and description values
(DescriptionValidationTable, FileValidationTable, CodeValidationTable).

To export descriptions, you must set an item property for your code item (Set
Export_Code_Description_State to True) and define your display item with a special
expression (entry_item (Code_Description(Current_Object)). The description item must
always be the item immediately following the code item.
A form in character mode:

Object My_form is an Entry_form customer_image


:
Item_List
Entry_Item Customer.Name
Entry_Item Customer.Id
Entry_Item Customer.Status
Set Export_Code_Description_State to True //tells above item
//to export
// description
Entry_Item (Code_Description(Current_Object))// defines item as
// a description field
Entry_Item Customer.Region
End_Item_List
:
End_Object

A grid in Windows:
Object My_Table is a dbGrid Main_File Customer
:
Begin_row
Entry_Item Customer.Name
Entry_Item Customer.Id
Entry_Item Customer.Status
Set Export_Code_Description_State to True
Entry_Item (Code_Description(Current_Object))
Entry_Item Customer.Region
End_Row
:
End_Object

The Export_Code_Description could be coded in any of the following alternative styles:


Set Export_Code_Description item CURRENT to True

Set Export_Code_Description item (Current_Item(Current_Object)) to True

Set Export_Code_Description item 2 to True // only if it is the third item

-46-
DataFlex 3.2 Data Dictionary Guide

Global or Dedicated Validation Tables?


Normally you will want to make a validation table object global. This makes the one object
available to any data dictionary that requires its validation services. In such a case, the
same list of valid items and descriptions is available to all data dictionaries. Global
validation-table objects must be placed outside the data-dictionary-subclass definition.
You may either create a package for the validation object and use it in your data-
dictionary subclass, or you may define the object immediately above your subclass
definition:

Object Status_Table is a CodeValidationTable


Set Type_Value to “Status”
Set List_title to “Customer Status Types”
End_Object

Class Customer_dataDictionary is a DataDictionary


Procedure Define_Fields
:
Set Field_Value_Table field Customer.Status to ;
(Status_Table(Current_Object))

Or you can place the validation object in its own package file and use it:
Use StatVal.pkg // creates object named Status_Table
Class Customer_dataDictionary is a DataDictionary
Procedure Define_Fields
:
Set Field_Value_Table field Customer.Status to ;
(Status_Table(Current_Object))

In the above example, the same physical validation object will be available to all objects.
In some cases, you may wish to create a unique object for certain data dictionaries. You
would only want to do that if each validation object needed to be different. In such a case,
you should place the object inside the define_fields procedure. When the
DataDictionary object(s) is created, a unique instance of the validation object will also
get created.

Class Customer_dataDictionary is a DataDictionary


Procedure Define_Fields
:
Object Status_Table is a CodeValidationTable
Set Type_Value to “Status”
Set List_title to “Customer Status Types”
End_Object
:
Set Field_Value_Table field Customer.Status to ;
(Status_Table(Current_Object))

You must not place this object directly inside the class. The validation object must get
placed inside a procedure or function (most likely define_fields). Because the object is
-47-
DataFlex 3.2 Data Dictionary Guide

defined within a procedure or function, you cannot place procedures and functions inside
the validation object. If you need to do so, you should create a subclass containing the
procedures or functions and then create an instance of that subclass.
Class Status_Table is a ValidationTable
Procedure Fill_List
Set List_title to “Customer Status Types”
:
Send Add_table_value “O”
Send Add_table_value “C”
Send Add_table_value “D”
end_Procedure
End_Class

Class Customer_dataDictionary is a DataDictionary


Procedure Define_Fields
:
Object Status_Table is a Status_Table
End_Object
:
Set Field_Value_Table field Customer.Status to ;
(Status_Table(Current_Object))

Creating Your Own Validation-Table Classes


The validation-table classes provided (ValidationTable, DescriptionValidationTable,
FileValidationTable, and CodeValidationTable) will probably handle all your validation-
table needs. If they do not, you are encouraged create subclasses. These classes have
been carefully created to provide optimum performance.

If you wish, you can create complete custom validation classes. You can make this class
work any way you want as long as it supports the pre-defined interface. When a validation
table is assigned to a field in a data dictionary, the data dictionary and the DEOs using it
expect this validation table to adhere to a specific interface.

A validation table must support the following public interface:

Get Static_State to State


Get Validate_State to State
Get Number_Elements to Val
Get Validate_Value data_value to State
Get List_title to TitleValue
Send Request_Fill_From_List ObjectId MessageId

As you can see, this interface is quite simple and abstract. It does not even specify if a
message should be represented as a function or a property. This is not relevant to the
-48-
DataFlex 3.2 Data Dictionary Guide

interface. The actual methods for processing these requests are internal and may be
quite complicated. As long as the interface is adhered to, you can make a validation table
act any way you wish.

Get Static_State to State

This property is used to specify whether display lists (popup prompt lists, combo drop-
down lists, and radio lists) should be refilled each time they are required by a DEO.
Normally, validation tables should be static (this property should be true). This will most
likely be used as a property.
Get Validate_State to State

This property specifies whether the list should be used for validation purposes. If true,
you will have to define the message get validate_value. This will most-likely be used as
a property.

Get Validate_Value data_value to State

If get validate_State is true, the message validate_value will get sent to this object. It is
passed the data_value to be validated. Returning a zero value indicates that the value is
valid; a non-zero value indicates that validation failed. The method used to validate this
value is left entirely to the class. This will most-likely be used as a function.

Get Number_Elements to value

This determines how many elements are used to represent a data item. This is used by
visual objects (prompt lists, combo forms, radio forms) to determine how to display data.
Currently the values 1 and 2 are supported. 1 indicates that only a data (code) value is
available; 2 indicates that both data and description values are available. This will most-
likely be used as a property.

Get List_title to TitleValue

Objects may request a title for a prompt list. This will most-likely be used as a property.

Send Request_Fill_From_List ObjectId MessageId

This message performs a very specific task. It is used when another object (prompt list,
combo form, etc.) needs to get filled with valid values. When it is received, the validation
object must send a specified message (MessageId) to a specified object (ObjectId),
passing information about each item in the validation table. The following information
must be passed back to ObjectId: Item number, Data value, Description value, File
-49-
DataFlex 3.2 Data Dictionary Guide

number, and Record Number. Item number and data value must contain information. If
Description value, File number, or Record number do not exist, you may pass empty
values (“”, 0, and 0), but five values must be passed back every time.
Example:

Procedure Request_Fill_from_List integer ObjectId integer MessageId


Local integer numItms ItmCnt
Local string DataVal DescVal
Get Number_Values to numItems // number of items in validation table
Decrement numItems
For ItmCnt from 0 to numItems
get data_Value item ItmCnt to DataVal
get Description_Value item ItmCnt to DescVal
Send MessageId to ObjectId itmCnt DataVal DescVal 0 0
Loop
end_procedure

This example assumes that your validation-table class defines and understands the
internal messages get number_values, get data_value, and get description_value.

The Local Field Buffer

Data dictionaries maintain a buffer of the current values of all fields of its data file. This
buffer is separate and distinct from the DataFlex record buffer. It maintains the current
value of each field as the field_current_value and each field’s changed state as
field_changed_state. This value is synchronized with any display values using that
file/field. This synchronization is mostly automatic. When a record is found, this local
buffer is updated with the contents of the DataFlex record buffer, and all
field_changed_states are set to false. When an entry item’s value is changed, the data
dictionary is notified of this change and the local field buffer’s value and changed_state
are updated. In addition, any other entry items using that file and field will also be
updated. When a record is saved, only the changed values are moved from the local field
buffer to the DataFlex record buffer.

A program may directly change a field value and/or its changed state by setting the
field_current_value and field_changed_state (or by setting the field_changed_value).
When this occurs, all entry items will be updated to reflect this changed value. Although
you may directly set an entry item’s value (which will set the field_current_value), this
practice is discouraged. Similarly, you should access a field’s value and not an item’s
value (although either will work).

The value in the local field buffer may not be the same as the value in the DataFlex file
(record) buffer. A file buffer (when current) will show the field’s original value as loaded
from the disk on the find. The field_current_value shows the field’s current value as

-50-
DataFlex 3.2 Data Dictionary Guide

entered from the keyboard or otherwise changed by the program. During a save, the file
buffer is eventually updated with the value from the local field buffer. In save and delete
hook procedures (update, backout, creating, deleting), you should use the values in the
file buffer and not the values in the local field buffer.

The Current_record Property

When a DDO finds a record, it places that record’s number in a property called
current_record. This property contains the record that the DDO thinks it is working with.
You can query the current_record property to find out if the DDO contains a record. If
you wanted to make it possible for a DEO to save new records but impossible to edit
existing records, you would augment the DEO’s request_save as follows.

// Only allow saves of new records.


// This is request save in a DEO, NOT in a DDO
Procedure request_save
Local integer Srvr
Get Server to Srvr // who is my server?
If (current_record(srvr) =0) Forward Send request_save
end_procedure

The DEO in the above example needed to find out if its DDO contained a record. Every
DEO has a property named server that returns the object ID of the DDO that it uses. In
this sample, we are finding the object ID of the DDO (the server) and then finding its
current_record. Make sure you understand this technique. It is used all the time.

While you can directly get the current_record property, you cannot directly set it. You can
set it indirectly by sending one of the finding messages.

The Finding Messages

The primary finding messages of DDOs are request_find, find_by_recnum, and


request_assign. The find messages find a record, perform a relate, set the appropriate
DEOs’ current_record properties, notify all other DDOs about the new record, and notify
all DEOs that are connected to the data-dictionary structure about the new record. It is
this notification process that makes DEOs attached to a data-dictionary structure act in a
coordinated fashion.

You will usually not augment the finding messages. Doing so is considered an advanced
technique. You will need to send finding messages to DDOs. This will be discussed in the
next section.

-51-
DataFlex 3.2 Data Dictionary Guide

Request Assign
If you find a record manually (with the find or constrained_find command) and want to
have the DDO “latch onto” and display the current record, you can send the
request_assign message. Request_assign will cause the DDO and its parent-file DDOs
to accept the record(s) in the buffer as their current record and refresh all affected DEOs.
Request_assign should be used with caution. The DDO does not check to see if the
records it is accepting are truly related. Because this is a manual process, it makes it your
responsibility to make sure that the records in the buffer are reasonable. Before sending
request_assign, you should make sure that all records in the buffers are proper.

Often you can use request_assign and find_by_recnum interchangeably. The following
two samples would yield the same result.

clear myfile
move 17 to myfile.recnum
find eq myfile.recnum
relate myfile
send request_assign to (myfile_dd(current_object))

or
send find_by_recnum to (myfile_dd(current_object)) myfile.File_number 17

How Data-Entry Objects Interact with Data Dictionaries

The goal of the high-level DataFlex data-entry packages is to make the interaction
between data-entry objects and their data dictionaries automatic. Because of this, you
really do not need to know the information provided in this section. It is provided so those
who are interested may gain a greater understanding of the DEO - DDO interaction
process.

Often this process involves the redirection of an “item” message to the data dictionary. An
entry item will contain the item properties data_file and data_field (which are set by the
entry_item command). When an item message needs to be redirected, it asks its server
(its DDO) to find the appropriate file and field for that item. The DEO’s DDO finds the
proper DDO for the requested file (itself or a parent DDO) and it then requests the
appropriate information for the requested field. This entire process is automatic and
knowledge of this process is not required to successfully use data dictionaries.

The following DEO item messages are redirected as follows:

1. Item Options - When a DEO is connected to its data dictionary, the data
dictionary’s field options are copied to the appropriate entry items. At this

-52-
DataFlex 3.2 Data Dictionary Guide

point, the data dictionary determines if the item represents a main-file or


foreign-file field. The appropriate field options are copied.
2. Item Entry, Exit and Validate Events - When an item generates item-
navigation or -validation events, the DEO will redirect this message to the
appropriate DDO. This way, all item-entry, -exit, and -validation events and
rules can be stored in the DDO.
3. Prompt and Zoom Objects - Whenever a prompt or zoom object is
requested (e.g., a user presses the Prompt key in an entry item) the DEO will
redirect the request for these objects to the data dictionary.
4. Status Help - Each time the cursor enters an item, a request is made to the
entry object for status help. The request is redirected to the data dictionary.

The term “redirection” is not entirely accurate. All the above processes have been
augmented to support data-dictionary field support in addition to the regular item support
provided by this item. If you wish, you may still set item options, item messages, and item
objects directly in the data-entry objects. The effects of the two settings will be additive.
For example, you can create an item-validation message (iValidate) in your DEO. This
message will get executed. If there is no validation error, the data field’s field-validation
message will also be sent. If you add item_options to an item, those items will be used
along with the field options defined in the data dictionary. This additive nature is not
stressed because you are encouraged to place as much of this type of code in your data
dictionaries and as little as possible in your DEOs. This strategy results in the maximum
reuse of code.

Although you can directly get and set the values of items in a DEO, you are encouraged
to do this through the data dictionaries. You should find that you rarely will need to access
field values in your data-entry objects. Most of this type of processing will occur inside the
data dictionary.

When you do need to access this information, there are two types of messages defined to
provide it. If you needed, you could first find the data dictionary that controls the
information required and then send a get/set field_current_value to that data dictionary.
This is too much work—easier methods exist.

The DEO File_Field and Item_Field Messages


If you know the data-file and field numbers of the data you need to access, you should
use file_field_ messages. The following file_field_ messages are supported within data-
entry objects.

get / set file_field_current_value


get / set file_field_select_state
get / set file_field_changed_state
-53-
DataFlex 3.2 Data Dictionary Guide

Both file and field must be identified. This can be done by passing both values or by using
the file_field clause.

Example:
get_fieldnumber customer.name to myfield
move customer.file_number to myfile
get file_field_current_value myfile myfield to myvar

produces the same results as:


get file_field_current_value file_field customer.name to myvar

When you set the value or the select state, all data-entry items in the view structure
connected to that field will be updated.

If you know the item number rather than the field number, you may access a field property
by using an item_field message. The following messages are supported:

get / set item_field_current_value


get / set item_field_select_state
get / set item_field_changed_state
Example:
get item_field_current_value item 7 to myvar

These messages are used extensively by the data-entry classes. You may never need to
use them.

Building Data-Dictionary Structures


A program usually contains many DEOs. Some of these objects should act in a
coordinated fashion with other objects. When a found record is displayed in one object,
that record should be displayed in some other objects as well. Other DEOs should be
independent. Changes made in one such DEO should not affect any other. The DDO is
the object that coordinates activities among DEOs. All DEOs that are connected to the
same DDO will act in a coordinated fashion.

DDOs also need to act in a coordinated manner with other DDOs. We accomplish this by
connecting the DDOs. An interconnected group of DDOs is referred to as a data-
dictionary structure. Each DDO in a structure might have one or more DEOs connected to
it. All of these DEOs will be coordinated. A save, delete, find, or clear operation in a DDO
will affect all DEOs connected to the data-dictionary structure in a coordinated and
hopefully intelligent manner.
This leads us to the most-important rule of DDOs:
-54-
DataFlex 3.2 Data Dictionary Guide

A DDO provides coordinated database services to every data-entry object that uses it,
and to every other DDO in its data-dictionary structure.

The above statement holds the secret to life in a DDO universe. If you want a DEO to act
in coordination with another DEO, you should make sure that both DEOs use the same
data-dictionary structure. Just as important, if you do not want a DEO to act in
coordination with another DEO, make sure that they are not using the same data-
dictionary structure.

A view is an object that contains a data-dictionary structure together with all of the DEOs
that use this structure. All of these DEOs will act in a coordinated fashion. This
coordination does not come about as a result of the fact that these objects all reside in the
same view. The coordination occurs if, and only if, the data-dictionary structure is properly
interconnected and each DEO is connected to the proper DDO. The view object simply
hides this complexity from the outside world.

DDOs are connected together with the set ddo_server message. Child-data-file DDOs
connect to parent-file DDOs. As a general rule, the child-to-parent file-updating links will
match the child-to-parent relationships you create in Database Builder. We will use the
following data-file structure as an example:

A B C
\ / /
D E
\ /
F
/ \
G H
In this diagram, parent files are above and child files are below. Files G and H relate to
File F. File F relates to both Files D and E. File D relates to A and B. File E relates to File
C. Files A, B, and C have no parents.

Creating a data-dictionary structure for these files is quite simple. Create the parent
DDOs first. Start at the top and work your way across from left to right. All connections will
be handled with an updating link (set ddo_server). The following shows how this file
diagram is rendered as a data-dictionary structure. The first step was to create a data-
dictionary subclass for each file. These classes contain all the database rules needed for
these files.
-55-
DataFlex 3.2 Data Dictionary Guide

Object A_DD is a A_DataDictionary


end_object
Object B_DD is a B_DataDictionary
end_object
Object C_DD is a C_DataDictionary
end_object
Object D_DD is a D_DataDictionary
set ddo_server to (A_DD(current_object))
set ddo_server to (B_DD(current_object))
end_object
Object E_DD is a E_DataDictionary
set ddo_server to (C_DD(current_object))
end_object
Object F_DS is a F_DataDictionary
set ddo_server to (D_DD(current_object))
set ddo_server to (E_DD(current_object))
end_object
Object G_DS is a G_DataDictionary
set ddo_server to (F_DD(current_object))
end_object
Object H_DS is a H_DataDictionary
set ddo_server to (F_DD(current_object))
end_object

Once your data-dictionary structure is created, your DEOs must be connected to the
proper DDOs. The server property of DEOs is used for this. In order to know where in a
data-dictionary structure a DEO should be connected, you must understand how DDOs
and DEOs interact.

When a DEO is connected to a DDO, the DDO is referred to as the DEO's server. A DEO
cannot perform any data-file activities itself. Instead, it will send a message to its server to
perform the function. A DEO will ask a DDO to save, delete, clear, or find a record. When
a DDO performs one of these operations, it will interact as needed with all other DDOs in
its structure. These DDOs will interact in turn with all DEOs that are connected to them. A
DDO sends two messages to a DEO. It will either ask the DEO to move data from the
object to the data-file buffer (entry_update), or it will ask the DEO to move data from the
data-file buffer to the object (refresh).

Propagation of Data-Dictionary Operations

DDOs perform these operations: save, delete, clear, clear all, and find. These operations
are usually initiated by a DEO sending a message to its server DDO. The DEO operation
is often initiated by users pressing a key. For example, a user may press the F2 key,
which will cause the request_save message to be sent to the DEO. The DEO will send a
message to its DDO, also called request_save. The DDO will then perform the save. If
-56-
DataFlex 3.2 Data Dictionary Guide

you understand how the five major data-dictionary operations behave, you can accurately
predict how your program will behave.

Saves - Request_Save

When a DDO receives a request_save message, it will attempt to save a record for its
main file. Saves propagate up. This means that a save can affect the main file of its DDO
and all of the DDOs above it in the updating chain. For example, if request_save is sent
to Object A_DD, a record in File A will be saved. If request_save is sent to Object D_DD,
Files D, A, and B will be saved. If request_save is sent to Object F_DD, Files F, D, E, A,
B, and C will be saved. What files would be saved if request_save is sent to H_DD? If you
answered all files except G, you would be correct. This implies that you must have your
parent-file DDOs properly connected if a data-dictionary save is to be properly processed.

It makes absolutely no difference what item the cursor is in when a user requests a save
in a DEO. The record that gets saved is determined by the DDO. If, for example, users
press F2 when they are in a vendor field in an entry form that is connected to a checks DDO,
a checks record will get saved. This may also save its parent vendor record (assuming the
data-dictionary structure is correct). If the entry form was connected to a vendor DDO, the
save would save the vendor record and not the checks record.

Deletes - Request_Delete

A request_delete attempts to delete the record from the DDO’s main file. If the
cascade_delete_state property is true, there are child-file DDOs in the data-dictionary
structure, and a relationship between the child and parent files is defined in the file
definition, the DDO will also delete the child records. This process will recurse down the
data-dictionary structure. Although a request_delete cannot delete a parent-file record, it
can update a parent file. This means that a request_delete will propagate up and down
the data-dictionary structure.
If the DDO’s cascade_delete_state property is false, the DDO will not delete a record to
which a record(s) in a child file(s) relates. Therefore, if a delete occurs, the propagation
direction will be up (just like a save).

If a request_delete were sent to Object H_DD, the record in File H would be deleted and
Files A, B, C, D, E, and F would be updated. A delete request sent to Object A_DD would
(if its cascade_delete_state is true) delete a record in A, delete all of A’s child records in
D, delete all of D’s child records in F, and delete all of F’s child records in G and H.
Deletes propagate up and down a data-dictionary structure. Deleted D records would
update File B. Deleted F records would update E and C. In other words, every DDO in the
file structure would be affected by a delete in A.

-57-
DataFlex 3.2 Data Dictionary Guide

This seems to suggest that you must have a complete data-server dictionary in place in
order to delete records in a parent file. If you want automatic deletions of child-file
records, this is true. Often you will want to prohibit deletes if there are child-file records
relating to the main-file record. You can use the cascade_delete_state property to
protect against this. If you disallow deletions of records that have children, deletes will act
the same as saves and only propagate up the data-dictionary structure.

This will determine how complete your data-dictionary structure needs to be represented
inside a view. If you need a view that can save and delete records from File A (it might be
a vendor file) and you are disallowing deletes if child records exist, the only DDO that will
be required in your view is A_DD. If you wish to be able to delete all child records, you will
need the complete data-dictionary structure.

A few things about deletes should be emphasized. The file that a record is deleted from is
determined by the DDO and not the DEO that sent the message. The record will be
deleted from the receiving DDO's main file. The propagation of deletes down to child
records is determined by the data-server updating structure and the relationships in the
files’ definitions. If either is missing, the child deletes will not occur. Constraints have
absolutely no effect on this process, but cascade_delete_state and the DD subclass's
client-file list (add_client_file message) do.

Clear and Clear_all

The clear_all message is simple. It clears every file in the entire data-dictionary structure.
Clear_alls propagate up and down.

The clear message clears the main_file of the DDO and then propagates up the data-
server structure. Clear does not propagate down. If clear were sent to D_DD, Files D, A,
and B would be cleared. The other files would be unaffected.

Finding

The primary find messages are request_find, find_by_recnum, and request_assign.


These messages are different from the other messages in that you can request a find on
a file that is not the main file of the DDO. For example, you could send request_find to
D_DD asking it to find a record in File A. The DDO will perform the find and then notify the
appropriate DDO (A_DD) about the results. This is important to understand. Operationally,
requesting a parent-file find in a child-file DDO is the same as requesting the find directly
of the parent-file DDO. After the find, the parent-file DDO will set its current_record
property to the correct record.

-58-
DataFlex 3.2 Data Dictionary Guide

The find is performed by the DDO that receives the message and not the DDO that owns
the finding file. After a find, the DDO will notify other DDOs in its structure about the new
record. This has some interesting implications for advanced usage. By augmenting the
find procedures in DDOs, you can make two different DDOs respond differently to finding
the same record. For example, we could augment the request_find message for DDO
D_DD as follows:

Procedure request_find Integer mode Integer File# Integer Indx


If File# ne A.File_number forward send request_find mode File# Indx
end_procedure

In this example, we have disabled any finding of File A records by DDO D_DD.
Request_find messages for File A that are sent to D_DD are ignored. All other finds are
processed, and a find sent directly to A_DD would also be processed.

A find operation will often result in the finding of parent records (the relate process).
When this happens, the parent-file DDO(s) is (are) properly notified of the new record.
Usually a DDO is requested to find a record in its main file or in one of its parent files.

A DDO’s current_record property determines what record the DDO will work with. There
will be times when the current_record in the DDO and the record in the file buffer will be
different. DDOs act on the current_record and not on the contents of the file buffer
(actually it will make sure that the buffer is loaded with the right record before a save or
delete). Simply finding a record does not make the DDO aware of a record. You must
send one of the finding messages to the DDO. This will set the current_record property.

Use the message request_assign if you want a DDO to latch onto the record in the file
buffer. This will perform a relate on the record, notify all concerned DDOs, and send the
message refresh to all DEOs that would be affected by this process.

Use the message find_by_recnum if you want a DDO to find a particular record. This will
find the record, perform a relate, notify all concerned DDOs, and send the message
refresh to all DEOs that would be affected by this process.

The request_find message will find a record for a selected file, in a selected direction, by
a selected index. It also performs a relate, notifies other DDOs, and refreshes the DEOs.
When these messages are used, they are usually sent from a DEO. Below are examples
of the usage.

// procedure inside a DEO


Procedure Do_Something
Local Integer Srvr# Rec# File#
Get Server to Srvr# // ID of DDO
:

-59-
DataFlex 3.2 Data Dictionary Guide

// latch onto record in vendor file buffer


Send request_assign to Srvr# Vndr.File_Number
:
// or, find a particular record for the main_file
Get Main_File to File#
Get My_Rec# to Rec# // user defined property
send find_by_recnum to srvr# File# Rec#
:
// or, find the next record for vndr by index.1
send request_find to srvr# GT Vndr.File_Number 1
:
End_Procedure

It is very helpful to understand how data-dictionary behaviors propagate. When you do,
you will be able to predict how DDOs will behave for any given operation. It will also help
you determine where DEOs should connect to a data-dictionary structure.

A Data-Dictionary-Propagation Quiz

Quiz 1
We have a data-dictionary structure (no constraints) as shown in the diagram. Our DEOs
could connect to any of these objects. For example, if our DEO were using DDO D, all of
the DEO’s data-file requests (save, clear, delete, find) will be handled by DDO D.

A B C
\ / /
D E
\ /
F
Clear All: What will happen if clear_all is sent to any of the DDOs? [All DDOs will be
cleared].

Clear: What will happen if clear is sent to A? [A is cleared.] What happens if clear is sent
to D? [D, A, and B are cleared.] What happens if clear is sent to F? [F,D,A,B,E, and C are
cleared.] Clears propagate up.

Save: What will happen if request_save is sent to A? [A is saved] What happens if


request_save is sent to D? [D,A, and B are saved.] What happens if request_save is
sent to F? [F, D, A, B, E, and C are saved]. Saves propagate up.

-60-
DataFlex 3.2 Data Dictionary Guide

Delete: (Cascade_delete_state is true in all DDOs.) What will happen if request_delete


is sent to A? [A will be deleted, A's children in D will be deleted, D's children in F will be
deleted. B,E and C will be updated]. What will happen if request_delete is sent to D? [D
will be deleted, D's children in F will be deleted. A,B,E and C will be updated]. What will
happen if request_delete is sent to F? [F is deleted, A, B, C, D, and E are updated].

Find: When a find request is made to a DDO, the file to find in is passed as a parameter.
You can request that a DDO find a record for its file or any of its parents’ files. Unless you
have augmented your find procedures, asking either DDO A or D to find a record for File
A will yield the same results.

What happens if a request_find for File A is sent to A? [A is found.] What happens if a


request_find for File A is sent to D or F? [A is found]. What happens if request_find for
File D is sent to D? [D is found and related, A and B are notified of the new related
records]. What happens if request_find for File F is sent to F? [F is found and related; A,
B, C, D, and E are notified of the new related records].

Quiz 2
We will give our data-dictionary structure the following values:

A B C A = Customer
\ / / B = Terms
D E C = Vendor
\ / D = Order Header
F E = Inventory
F = Order Detail
F has a relates-to constraint to D.
DEO_Header_Entry is using D.
DEO_Table_Entry is using F.

We now have a standard order-file structure. We will hook two DEOs to this structure: an
order-header-entry form using D and an order-detail grid using F. This means that users
will only be sending data-dictionary requests to DDOs D and F. Without a relates to
constraint between F and D, the data-entry behaviors will not be appropriate for our entry-
form/grid setup. The save and delete behaviors are fine; the clear and find behaviors are
not.

We must add a relates to constraint in DDO F which will constrain F records at any given
moment to only those relating to the current record of its Parent File D. Constraints have

-61-
DataFlex 3.2 Data Dictionary Guide

no impact on saving or deleting (which is good). They do change the clear and find
behaviors (which is also good).

Clear: What happens if clear is sent to D? [D, A, and B are cleared, D will notify its
constrained child, F, that it has a new blank record. F will attempt to find a record that is
related to the blank child. Hopefully it will fail, clearing F, E, and C. The net result is that all
files are cleared.] What happens if clear is sent to F? [F, E and C are cleared. When F
attempts to clear DDO D, it will "bump" into the relates to constraint and halt the clear up
that tree branch.]

Find: What happens if a request_find for File A is sent to D or F? [A is found, nothing


else is changed]. What happens if request_find for File D is sent to D? [D is found and
related. A and B are notified of the new related records. In addition, D will notify its
constrained child file F about the new parent record. F will find the first valid record and
tell the grid object about the record. The grid object will fill in the grid with valid records.
Files E and C are related and their DDOs are notified of the change. Therefore, when D is
changed, the child grid record will change as well. This is good.] What happens if
request_find for File F is sent to F? [F is found only if F is a valid child for D. Therefore
D, A, and B cannot change. Files E and C are related and their DDOs are notified of the
change.]

The header object will contain the fields allowing us to find the customer records (A). We
did not choose to constrain the order header file to the customer file. For finding
purposes, we do not want our search of orders to be limited to a single customer. We did
not create a separate DEO for the customer fields. If we had done this (and that DEO was
using the customer DDO), we would have gotten undesired save and delete behaviors.
Save would have only saved the customer file. Deletes would have deleted the customer
record and all of its children.

Quiz 3
We will now create a view for customer entry. We will base the view on a single DDO.

A A = Customer

What are the implications of removing the child-file DDOs? If you review our data-
dictionary-propagation rules, you will note that the only behavior that would propagate
down is a delete. Saves propagate up. Since we have no parent files, this operation will
be fine. If the child-file DDOs are not provided, a delete will not delete any child records.
This means that we would end up with “orphan” records (orders). Normally we do not
want this. We will control this in the DDO’s cascade_delete_state property, making it
impossible to delete customers that have child records.

-62-
DataFlex 3.2 Data Dictionary Guide

How complete does your data-dictionary structure have to be? Locate the childmost-file
DDO, which will have a DEO using it. Make sure that all parent-file DDOs are in your
structure and properly connected. If not, your saves and deletes may not work properly. If
you are disallowing deletes of records that have children, you will not need to create any
DDOs below the lowest “used” DDO. If you are allowing child-record deletes, you must
make sure that the child DDOs and all of those DDOs’ updated DDOs are provided and
connected.

“Diamond” File Structures

Data-dictionary structures can support “diamond” relationships. A diamond relationship is


one where a parent file can be reached from a child file by more than one path. Consider
the following example:

A B C
\ / \ /
D E
\ /\
F I
/ \ /
G H

In this example, there are two diamond relationships (Files B and E are the tops of each
diamond). When File F finds a record, there are two paths it can use to find related Parent
B ( F—>D—>B or F—>E—>B). This kind of structure is supported as long as the
relationships are proper. If Record B can be reached by two paths, then you must make
sure that the record that will be found in B will the same using either path. In other words,
the records in D and E must have the same parent in B. Similarly, the records in F and I
must have the same parent in E. As long as these rules are obeyed, diamonds are fully
supported. The updating structure of your data dictionaries should reflect the diamond
structure. The redundancy in updating links will not cause any problems; DDOs will take
this redundancy and optimize it.
Summary

It is critical that you understand how data-dictionary operations behave and propagate. If
you do, you can accurately predict how your views will behave. Below is a summary of the
data-dictionary operations and their behaviors.

-63-
DataFlex 3.2 Data Dictionary Guide

Data-Dictionary Normal Behavior Constrained Behavior


Operation
clear_all Clears all connected DDOs same
clear Clears DDO and all updated Clears DDO and all updated
DDOs. Propagates up. DDOs unless a relates-to
constraint is encountered. The
clear up that branch will be
halted. Child DDOs with a
relates-to constraint are notified
of the new blank record. It will
clear or find as required.
request_save Saves DDO record and same
updates all parent-file DDOs.
Propagates up.
request_delete Deletes DDO record and same
updates all parent file DDOs.
Child records are deleted if
their DDOs update the parent
DDO and
cascade_delete_state is true.
Propagates up and
(conditionally) down.
finding Finds record for the requested If the file’s DDO has a relates-to
file. A relate is performed. All constraint in effect, only records
DDOs are notified of the will be found that satisfy the
change, setting each DDO's constraint's requirements. Child
current_record as needed. Any DDOs with a relates-to
DEO that uses any affected constraint are notified of the new
DDO is refreshed. record. It will clear or find as
required.

Connecting More Than One DDO to the Same File


It is expected that your applications will contain multiple views and that some of these
views will need to use the same data file. Each view will have its own DDO(s)
encapsulated inside it. Each of these DDOs has the same main file, the same data-
dictionary subclass, and will probably even have the same name. Further, all of these
objects will share the same, single file buffer. As long as you don’t try to put two DDOs
based on the file in the same view, you will not have any problems.

The critical database operations are save and delete. These operations are safe. A DDO
will make sure that it has the correct data in its file buffer before it proceeds. This is all
automatic. This means that the buffers are correct when most of the data-dictionary
-64-
DataFlex 3.2 Data Dictionary Guide

messages are processed (update, backout, deleting, validate_save, validate_delete,


etc.). The DDOs notify DEOs that they need to display data by sending the DEOs the
refresh message. The data-file buffers are correct during the refresh process.

There are times when the data-file buffers are not to be trusted. During data entry, it is
possible that the file buffer will not contain the data you think it does. If a user switched
views in the middle of a process, it is possible that the record that the DDO thinks it is
working with (which is identified in the DDO’s current_record property) is not the record
that is in the buffer. This doesn’t bother the DDO, but it may get you in trouble if you have
DEO code that is based on the contents of a file buffer. There are several easy ways to
get around the fact that file buffers are not to be trusted.

• Whenever possible, use the value of the object instead of the value of the
database field to which the object is connected.
• When you need to deal with a value that is not stored in an object, you will
have to use the file buffer. Before you use the buffer, you must send a
message to the DDO telling it to make sure that the buffer is correct. The
message is refind_records. The standard method of sending this message
is:

Send refind_records to (server(current_object))

For example, we might have a field_entry_msg procedure that loads a form with a
default credit-card number from a record to appear when the field is entered. The property
setting and the entry procedure follow:

field_entry_msg item 0 dflt_cc


:
Procedure Dflt_CC integer item#
// only change blank unchanged items
if (value(current_object, item#) ='' and ;
item_changed_state(current_object, item#) =0) begin
// first make sure the file buffer is right
send refind_records to (server(current_object))
set value item item# to Cust.CC_Num
set item_changed_state item item# to true
end
end_procedure

Using System Files in Data Dictionaries


DataFlex system files are designed to contain only one record. You can apply this
attribute by setting the database file’s maximum number of records to one (1) in Database
Builder. System files can be the main file or an updated file of a DDO, and should be
treated just like a related file.

-65-
DataFlex 3.2 Data Dictionary Guide

Additionally, system files should never be cleared and their (only) record should never be
deleted. Consequently, DDOs prevent these two operations from being performed on
system files. Furthermore, since a system file’s record is automatically found when the file
is opened, manually finding the record is unnecessary. As a result, the only time a DDO
redisplays the data for a system file is after the system file has been saved. (If you wish to
redisplay it, you can send the entry_display message, passing the explicit file number of
the system file.)

Often system files are not assigned a DDO. System files represent the one exception to
the Framework rule that states that a data-dictionary subclass should be created and
used for every data file in an application. Instead, you may name the file in an
add_system_file message, whose syntax is:
add_system_file integer file_number [integer lock_type]

This procedure adds file_number to the data-dictionary structure. It is used for system
files and other files that, although part of the locking structure, do not have their own
DDOs through which to connect to the data-dictionary structure. Lock_type specifies the
type of locking to be used with file_number:

DD_lock_on_all Lock on all saves and deletes


DD_lock_on_new_save_delete Lock on new saves and deletes
DD_lock_on_save Lock on all saves
DD_lock_on_new_save Lock only on new saves
DD_lock_on_delete Lock only on deletes

For system files supporting unique ID serial numbers, DD_lock_on_new_save should be


sufficient; for files supporting counters that increment and decrement, the other two
modes would be required, so DD_lock_on_all would be appropriate. System files can be
detached with remove_system_file.

Send Add_System_File OrdSys.File_Number DD_Lock_On_New_save

You may create a system-file data-dictionary subclass and object and connect this DDO
to your data-dictionary structure. If you do this, you would not need to save the system file
in your creating procedure; the DDO will do this for you automatically. If you do this, you
should make sure that any DDO that directly uses the system file explicitly connects to the
system-file DDO with an updating link. In the following example, both customer and order
use the system file sysfile to supply record keys. Therefore, the DDOs for both directly
provide an updating link to the system-file DDO:

object order_ent is an entry_view_client


object sysfile_dd is a Sysfile_DataDictionary
end_object

-66-
DataFlex 3.2 Data Dictionary Guide

object customer_dd is a Customer_DataDictionary


set ddo_server to (sysfile_dd(current_object))
end_object
object Order_dd is an Order_DataDictionary
set ddo_server to (customer_dd(current_object))
set ddo_server to (sysfile_dd(current_object))
end_object
:

Constraints
A constraint is a restriction on what records in a file are visible to a program. There are
three reasons that you might want to constrain a file in a DDO:

• When one DDO relates to another, you generally want the child DDO to only
show the records which relate to the current record in the related-to (parent )
DDO. A relates-to constraint (in the child DDO) will do this for you.
• You may want a DDO to look like a file, but that "logical file" is actually a
selection of records from some larger file. For example, your customer DDO
may actually be a general-purpose name and address file constrained to
address.type eq "customer". A constant-value constraint will do this for you.
• An application may only be concerned with a subset of records at any one
time. You could specify customers and a given region and/or tax bracket. An
arbitrary constraint will do this for you.
The Constrain Command
The constrain command may be used in the following ways:
constrain order relates to customer

The above statement would normally be used in the DDO for order. It makes all finds in the
DDO reflect only those records that relate to the current customer record. For example, if
the customer Sandbag Quarry had previously been found in the customer file, a find in the
order file would be constrained to only find orders for Sandbag.

constrain order.type eq "FUTURE"

This type of constraint will require that all finds in the order file match FUTURE. If a find is
done and a record does not match FUTURE, the system will continue finding records until
one matches all the constraints. You may use all of the standard operators here, lt, le, eq,
ge, gt, ne. You may also use contains, which requires that the field contains the value
and matches, which is similar to eq, but allows wild card characters (* and ?), and only
works on strings. The value argument of the constraint may be any type of variable, but
the constraint will not change as the value of the variable changes. (You can send
rebuild_constraints to force the changed value to be used, as discussed later.)

-67-
DataFlex 3.2 Data Dictionary Guide

constrain order.recnum between 1 and 100

The above constraint will set a range for any field value. In all other ways, it is the same
as the value constraint, above.
constrain customer as (((customer.name contains "DATA") or;
(customer.type ="COMPUTER")) and ;
(customer.area_code matches "3"))

The expression constraint, above, is the most-flexible. You may put any expression you
wish, of any level of complexity. The expression must return a true or false value. You will
usually use the expression comparisons with and/or to do this. You may also call
functions within the expression. However, due to its flexibility, this is also the slowest
constraint type. The expression is evaluated each time a record is checked to see if it
satisfies the constraint. In addition, an expression constraint has no way of optimizing its
finds (it cannot jump into or out of an index), so it can be very slow in large files and/or
with complex expressions. Use the other forms of the constrain statement whenever you
can.
Programming Constraints in DDOs
Within a DDO, all of your constrain statements are put in a constraint block like this:
begin_constraints
constrain order relates to customer
constrain order.type eq "FUTURE"
end_constraints

All the constraints in the block are additive, that is, all must be satisfied for a record to be
found.

The constraints are automatically built when the DDO is constructed at run time and are
then enforced for any find. Consequently, the data files must be open at the time the
DDO is constructed. Note that you must use the find messages of the DDO for the
constraints to be used—the find command will not respect constraints. As an alternative,
you may use the constrained_find command, along with the other constraint-oriented
commands. See the DataFlex Command Reference for complete information on their
use.

Normally, constraints belong in data-server objects and not in data-server classes.


Constraints are used to limit the program's view of the data. This type of restriction tends
to be based on the requirement of a view rather than on a general database rule.

-68-
DataFlex 3.2 Data Dictionary Guide

Variable Constraints
You may have constraints that should change based on user input or other conditions.
For example, you may want users to fill in the country of the customers to deal with and
then constrain the DDO to that country. Since constraints are built when the object is
constructed, these changes in constraints would not normally be reflected (except in
expression constraints, which are evaluated every time). Whenever the criteria on which
the constraints depend may have changed, send a rebuild_constraints message to the
DDO. This will rebuild the constraints with the current data values. Often after changing a
constraint, you may find that your current record is no longer part of the valid constraint
set. Because of this, you will often need to find a new first record after rebuilding a
constraint.

In the following example, a DEO sends a message to its DDO passing two parameters,
the new constraint value and the index to use for finding a new first record:

Object Customer_DD is a customer_dataDictionary


property string status_constraint public ''
Procedure Constraint_by_status string stat integer ndx
local integer file#
get main_file to file#
Set status_constraint to stat
send rebuild_constraints
send request_find FIRST_RECORD file# ndx
end_procedure
Begin_constraints
Local string stat
get status_constraint to stat
if stat ne '' constrain Customer.status eq stat
End_Constraints
end_object

Constraint Search Optimization


If the DDO had to scan the entire database for every find, users could be waiting a very
long time to find a record or set of records. The DDO will try to optimize the search by
using the index you have programmed to find by and "jumping into" the index. Whenever
a find is executed, the constraints are evaluated with the index in use to see if any
optimization can be done. This is automatic—you don’t have to program anything further
to make this happen. However, if the current index can’t help the search, the DDO could
have to scan the entire database. If you want to force the database to always use a
particular index to ensure that it finds quickly, you may specify an order on the DDO with
the by index.# clause. Specifying an order forces all finds (including those initiated by
users) to use that index.

-69-
DataFlex 3.2 Data Dictionary Guide

Advanced Data-Dictionary Topics

“Picture” Masking for Display and Data Entry


Using the field_mask_type property, and/or the associated field_mask property, you can
restrict data entry to a field to a defined pattern of numbers, letters, and punctuation
marks, and provide displays of field values complying with such pattern with the addition,
if desired, of literal characters and/or translations of numeric values to names and
abbreviations such as days of the week or months of the year. Translating from numbers
to names is sensitive to the Windows locale settings at using sites. Where you may have
seen Januar as the first month on your system, users with English-language locale
settings will see January, while those with French-language locale settings will see
Janvier. Attributes such as date-component order are under the control of the masking
you specify for display, and under the control of local environment settings for data entry
(except that DataFlex always requires four-digit entries for years). Data entry is done
numerically even in fields that are masked for display of names of months, days, etc.

Non-token characters in mask strings are treated as literals (are inserted where seen into
masked field values). This includes the space character. Token characters can be
deactivated and made to appear as literals in masked values by preceding them with a
backslash (\).

Picture masking is not validation. In fact, the picture-masking data types can frustrate
certain kinds of validation. An example is the mask_date_window type. An item to which
data entry is done through this type might receive an entry of 13/13/13, a value that
DataFlex’s basic Date type would reject as invalid by declaring an error.
Mask_date_window, however, would accept this value, converting it to something like
the thirteenth day of the first month of the fourteenth year (itself a valid date). For
reasons such as this, you may choose not to use picture masking on validated fields, or
perhaps on fields to which data entry is made. Picture masking never returns an error, nor
rings the bell—it just discards ineligible characters. By default, data is stored to disk only
in the form in which it is entered (numerically). Entry of the day of the week is not
supported, but display of day of the week for actual dates is.

Masking can also be programmed in DEOs. The primary reason for doing this would be
because of some local requirement in a DEO for a departure from the masking applied
(or not applied) in the pertinent DDO(s). See ‘“Picture” Masking for Display and Data
Entry’ on Page 70. The primary place for application of masking is in DDOs.

-70-
DataFlex 3.2 Data Dictionary Guide

Mask strings for fields are set in the define_fields procedure as field_masks. Mask
types for fields are specified as field_mask_types. A final field property is
field_mask_value_state, a boolean (default: false) that controls whether mask
characters get saved to the disk together with “raw” input values. The default provides for
saving only the numeric values, but direct reporting of field values can be easier to read
with the mask characters, especially when the output does not need to be sorted on the
masked field. For foreign files, there are, as always, a file_field_mask_type, a
file_field_mask, and a file_field_mask_value_state.

It is rarely necessary to set both a field_mask and a field_mask_type for a field.


Inherently, fields have data-type attributes, and length and precision attributes that can be
used to infer mask attributes. Where these are not in conflict with what you desire, just
setting one of these (field_mask_type is easier to remember in a way that will not conflict
with defaults and field attributes) will often suffice, together with the global defaults
discussed below.

You can change the global defaults (default_currency_mask and


default_numeric_mask) by changing the string(s) itself in DFBASE.PKG. Where you
wish to change the “global” string(s) only for a program, you can change the string(s)
immediately after the use dfallent statement.

In that variables can be passed to these properties, the effective mask strings for
compiled programs can be passed to them without recompilation through a system file,
profile string, or such for localization purposes.

Field_mask_types can be:


mask_window
mask_date_window
mask_numeric_window
mask_currency_window

General String Masking

Mask_window is a general-purpose type, and has no translating or other locale-sensitive


elements. These are its tokens and their meanings:
Token Meaning
# any numeric digit (0-9)
@ any alphabetic character
! any punctuation character
* any single printable character

-71-
DataFlex 3.2 Data Dictionary Guide

Here are examples of mask_window masks:

Mask Data Formatted Text


###-##-#### "012345678" 012-34-5678
###-##-#### "012-34-5678" 012-34-5678
(###) ###-#### "2125551212" (212) 555-1212
(###) ###*#### "212-555-1212" (212) 555-1212
@@@, #### "Feb-2002" Feb, 2002

Date Masking

These are the tokens and their meanings for the mask_date_window type:

Token Meaning
m month 1-12
mm month 01-12
mmm local month-name abbreviation jan-dec (case-sensitive)
mmmm local month name january-december (case-sensitive)
d day 1-31
dd day 01-31
ddd local day of week abbreviation sun-sat (case-sensitive)
dddd local day of week sunday-saturday (case-sensitive)
yy 00-99
yyyy 1700-2900
/ diagonal is replaced with the local date separator

The tokens for month and day names are case-sensitive. That is, Mmm would produce
Apr, while MMM would produce APR for the fourth month. Here are example
mask_date_window strings:

Mask Data Formatted Text (USA locale)


Ddd - Mmm d, yyyy 9/22/08 Tue - Sep 22, 2008
m/d/yy 9/22/08 9/22/08
Mmmm d 9/22/08 September 9

There is no default date mask string. When setting field_mask_type to


mask_window_date, you must also set the field_mask property.

-72-
DataFlex 3.2 Data Dictionary Guide

Number and Currency Masking

These are the tokens and their meanings for the mask_numeric_window and
mask_currency_window types:

Token Meaning
, comma inserts local thousands’ separator every three places to the left of
the decimal
. period is replaced with the local decimal indicator
; semi-colon comes after format for positive quantities, before format for
negative numbers
# no digit or one digit
* any number of digits, including none
0 one digit, or a 0 (zero)

Here are examples of mask_numeric_window and mask_currency_window masks:

Mask Data Formatted Text (USA locale)


$#,##0;($#,##0) 1001.536 $1,002
$#,##0;($#,##0) -1001.536 ($1,002)
0.00 -0.2 -0.20
00000 123 00123
-> * <- 104 -> 104 <-
*0.* 30.2500 30.25
+*0.00;-*0.00 12 +12.00

General-Number Masking
General numbers are supported in picture masking by the mask_numeric_window
field_mask_type. The global default mask string (default_numeric_mask) for this type
is *. This is a placeholder for a more-specific mask of your own, and imparts no formatting
(other than type-checking) of its own. The precision is inferred for each field from the
precision of the field itself.

Where you need a mask unrelated to any field, or different from the field(s) to which it
may apply, the easiest way to create the needed mask is to generate it using a global
function, number_default_mask This function returns a mask string for numbers from
the lengths and tokens you pass to it:

-73-
DataFlex 3.2 Data Dictionary Guide

Number_Default_Mask iLeftDigits iRightDigits sTemplate returns string

Argument Explanation
iLeftDigits The maximum number of digits to appear to the left of the
decimal
iRightDigits The number of digits to appear to the right of the decimal
sTemplate An asterisk and other tokens and literals to guide generation of
the desired mask

The "*" symbols in template are replaced in the returned mask with a digit expansion
using the proper number of "#" and "0" mask characters. Zeros "0" are returned for the
first digit to the left of the decimal, and for all digits to the right. The hatch "#" is always
used for all left digits except the first. Examples:

iLeftDigits iRightDigits sTemplate Mask returned


6 0 * #####0
6 2 * #####0.00
6 2 £,*;(£,*) £,#####0.00;(£,#####0)
10 0 ¥,* ¥,#########0

As the examples suggest, this function is suitable for generating masks both for use with
general numeric and currency amounts.

Where you need a mask for a Number field, the numeric_mask property is usually most-
convenient. This is its syntax:

set numeric_mask item item_num to leftDigits rightDigits [maskString]

Argument Explanation
item_num The number of the item to which this setting applies
leftDigits The maximum number of integers to be allowed to the left of the
decimal
rightDigits The fixed number of integers to be displayed to the right of the
decimal
maskString An optional replacement for the default mask string

Currency Masking
Currency is supported in picture masking by the mask_currency_window
field_mask_type. The global default mask string (default_currency_mask) for this type
-74-
DataFlex 3.2 Data Dictionary Guide

is $,*;($,*). This imparts a dollar sign as the currency character, and use of the local
thousands’ delimiter every three places to the left of the decimal. The currency character
will “float” to the immediate left (no intervening spaces) of all values displayed. The
precision (usually two digits to the right of the decimal and a suitable magnitude to the
left) is inferred from the precision of the field addressed. Where a different precision is
desired for a field and/or a different mask string, this can be imparted to the field by
setting the currency_mask property for it. The syntax for this property is:

set currency_mask item item_num to leftDigits rightDigits [maskString]

Argument Explanation
item_num The number of the item to which this setting applies
leftDigits The maximum number of integers to be allowed to the left of the
decimal
rightDigits The fixed number of integers to be displayed to the right of the
decimal
maskString An optional replacement for the default mask string

Probably the commonest use of this property would be to either delete or add (zeroes for)
fractional (decimal) values to or from field values. Providing a maskString would be
unusual unless there were a need for only one field to vary, for example, the currency
character. Providing zero-filling for the whole-number component would also entail a
change via maskString.
Controlling “Cascading” Deletions
The behavior of cascading deletes is discussed above. A DDO will delete all relating
records in all descendant data files if they are part of the data-server structure and a file
relationship exists with the files. In some cases, this is what you want; in others, it is
expressly not what you want. Where you wish deletions of main_file records having child-
file records to be prevented, use the cascade_delete_state property. DataFlex is shipped
with this property true for all DDOs, providing for the behavior just described. You can
change it for all DDOs in programs you compile by changing the line

DEFINE DEFAULT$CASCADE$DELETE$STATE FOR TRUE

in DFALLENT.PKG to FALSE. You can, alternatively, set the property false in individual
DDOs (and/or their classes).

Setting the property false by itself will disable the deletion of child-file records (even if
children exist). This is not the purpose of this message. It is expected that you will identify
in the main DDO, the child files on which you wish this protection to be based. This you
can do with the add_client_file message, with an argument of the number of the file on
-75-
DataFlex 3.2 Data Dictionary Guide

which you wish the protection to be based. You must provide one message for each child
file for which you desire it, normally in the construct_object procedure of the data-server
subclass definition.

When this is done, the main_file record will not be deleted when a named child file
contains a record that relates to the record to be deleted nor, of course, will any child-file
record. If no named child file contains such a record, but a child file not named contains
such a relating record, the main_file record will be deleted, but not the child records in
the unnamed file(s). This behavior is probably undesirable, so you should make sure that
you have properly listed all child files.

The checking of the named files is done by a procedure called by the validate_delete
function, called validate_delete_no_cascade. If you have your own validate_delete
definition, you must forward get validate_delete in order to have cascade-delete
protection.

If validate_delete_no_cascade encounters a named file that is not open, it sends


operation_not_allowed with an error-number argument that produces the message
Cannot delete - related files not open. If it finds a named file with a relating child record,
it sends the same procedure with the argument Cannot delete - related records exist. If
you need to perform custom cascade-delete validations, you may augment or override the
function. If you wish to stop the delete, you should send the message along with an
appropriate error number.

You can remove protecting files from the container-file list with the remove_client_file
message. You can query the number of protecting files in the list with the
client_file_count function, and you can acquire the number of the file in any particular
position on the list with the client_file function. It is not expected that you will need to use
either of these messages.

DataFlex is shipped with this property true for all DDOs, meaning that a cascade delete
will be attempted. You can change this default for all DDOs in programs you compile by
changing the line

DEFINE DEFAULT$CASCADE$DELETE$STATE FOR TRUE

in ALLENTRY.PKG to false. (Remember to recompile.) You can, of course, set the


property false in individual data-server subclasses and/or objects.

Smart Data-File Locking


The default behavior of saving or deleting is to lock and reread all open files in the file list
for the time required to effect the save to disk. In a structure of many related files, with
-76-
DataFlex 3.2 Data Dictionary Guide

many rereads in parent, and sometimes child, files, this can disrupt saving or deleting
activities by other users seriously (it does not inhibit finding or editing activities).

DDOs support a feature named "smart filemode" that can substantially improve the
performance of saves and deletes. This controlled by a DDO property named
smart_filemode_state. When all DDOs in a data-dictionary structure set this property to
true, only the data files that will actually participate in the operation will be locked and
reread. This can significantly improve performance on the workstation performing the
operation, as well as on workstations not performing the operation at that particular time
(there is less network traffic).

Basic Smart-Filemode Usage

It is very easy to implement smart filemode. When a save or delete occurs, the DDO
performing this operation will scan all participating DDOs in the structure. If
smart_filemode_state is true for all of these DDOs, the DDO will use smart-filemode
locking.

By default, smart-filemode is enabled in data-dictionary objects and no change is


required. If for some reason your DDO structure cannot support smart-filemode, you may
disable this by setting smart_filemode_state to false. You would set this inside the
define_fields procedure in the subclass. You should avoid doing this, and should instead
apply your efforts in creating a data-file structure that supports smart filemode.

Class Myfile_DataDictionary is a DataDictionary


Procedure Define_Fields
forward send Define_Fields
set main_file to myfile.file_number
set smart_filemode_state to false
:
end_procedure
:
end_class

By default, smart filemode is disabled in data sets and must be enabled by setting
smart_file_mode_state to true. You would set this inside the construct_object
procedure in the subclass.

-77-
DataFlex 3.2 Data Dictionary Guide

Class Myfile_DS is a DataSet


Procedure Construct_Object
forward send construct_object
set main_file to myfile.file_number
set smart_filemode_state to true
:
end_procedure
:
end_class

Handling Exception Files

This works well for all DDOs that only use data files that are known to the data-server
structure (the main_file of each participating DDO). What happens if you need to use a
data file that is not known to the data-server structure? System files are commonly used
only through procedure creating (to create system-supplied record keys). Files of this
kind are considered “unknown” to the DDOs involved, and handling them in a smart-
filemode milieu requires certain steps beyond those described above.

Handling Exception Files in Data Dictionaries


You inform a data dictionary about “unknown” files by sending the message send
add_system_file. This informs the DDO that the passed file number should be locked
during saves and deletes. An additional lock-type parameter may be passed, allowing you
to specify under what conditions the exception file should be locked (lock on all [the
default], lock on save, lock on new save, lock on new save and delete, and lock on
delete).

In the following example, the data-server subclass is informing the DDO that a system file
must also be locked, but only during the saving of a new record:

Class Myfile_DD is a DataDictionary


Procedure define_fields
forward send define_fields
set main_file to myfile.file_number
send add_system_file sysfile.file_number dd_lock_on_new_Save
define_auto_increment sysfile.counter to myFile.ID
:
end_procedure
:
end_class

If you use data sets and not data dictionaries or you have need to handle even more-
complicated exception-file conditions, you must augment the procedure
reset_filemodes_for_lock.

-78-
DataFlex 3.2 Data Dictionary Guide

Handling Exception Files in Data Sets


You inform a data set about "unknown" files in the procedure reset_filemodes_for_lock.
After forward-sending the message, you can manually set the filemode of any file.
Typically you will set the filemode of any unknown files to read/write (default). The
reset_filemodes_for_lock message is sent to all participating DSOs in a data-server
structure.

In the following example, the data-set subclass is using smart filemode and is informing
the data set that a system file must also be locked:

Class Myfile_DS is a Dataset


Procedure construct_object
forward send construct_object
set smart_filemode_state to true
set main_file to myfile.file_number
end_procedure
procedure reset_filemodes_for_lock
forward send reset_filemodes_for_lock
file_mode sysfile default
end_procedure
:
end_class

If your system file is controlled via its own updated DSO, you would not need to make this
provision. The DSO would know about this system file because it is part of the data-server
structure.

Optimizing System-File Access


Once file-access and saving-time factors have been improved with smart filemode,
access to system files shared by many users can still present a bottleneck. One method
of alleviating this problem is to divide up the fields in the system file that need to be written
to into groups that can be used independently of each other. Often, a single field makes
up such a group. Each of these can be moved to its own, separate system file. While this
is very effective, it does have the disadvantage of requiring more data files in your file list.
You could run out of room for these new entries.

One simple alternative for a common type of system file that only needs to be locked
when a new record is being created would be to make the filemode-changing shown in
the example above conditional. The send add_system_file statement would be extended
somewhat, as shown in boldface:

add_system_file sysfile.file_number DD_lock_on_new_save

-79-
DataFlex 3.2 Data Dictionary Guide

In this example, we only lock the system file when we need to use it. We only need it
when a new record is being saved.

If you are using data sets, this would be coded in reset_filemodes_for_lock as follows:
Procedure Reset_Filemodes_for_lock
Local integer crec
Forward Send Reset_Filemodes_for_lock
Get Current_Record to crec // if 0, a new record
// only lock the system file if we need it. We need it when
// we are saving a new record
If crec eq 0 file_mode sysyfile Default
End_Procedure

How Smart Filemode Works

When a save or delete request is sent to a DSO, the following occurs:

1. Check if smart filemode should be used.


2. The smart_filemode_state property of all participating DSOs is checked. If
any DSO’s smart_filemode_state property is false, smart file locking will not
be employed (and the following steps will not be executed).
3. Record the current filemodes of all files.
4. The filemodes of all files are recorded in an internal array.
5. Set filemodes of all files to read-only.
6. Actually, the files are set to the value of the smart_filemode_for_no_lock
property (which is DF_FILEMODE_READONLY by default), thus making
them exempt from locking from the program in which this is happening.
7. Set all participating files’ filemodes to read/write.
8. The message reset_filemodes_for_lock is sent to all participating DSOs,
where it sets the filemodes of participating files to the value of the
smart_filemode_for_lock property (the original mode, by default). Any
custom augmentations occur at this point (such as marking a system file for
participation).
9. The save/delete itself proceeds.
10. Only the files with filemode other than DF_FILEMODE_READONLY are
locked and reread.
11. The filemodes of all files are restored to their original states.

Smart Filemode and Alias Files

Smart filemode’s default behavior takes account of alias files (filemode of alias or
master_alias) that are participating in the save/delete. The master file is set to the mode

-80-
DataFlex 3.2 Data Dictionary Guide

of smart_filemode_for_lock, but with the DF_FILEMODE_NO_LOCKS bit turned off


(thus the master-alias file is always locked). The alias files are all set according to
whether they are participating in the save/delete, but with the
DF_FILEMODE_NO_LOCKS bit turned on (thus alias files are never locked). Master-
alias files are locked and reread, while participating alias files are reread but not locked,
which avoids a deadlock condition. Smart filemode uses the value of the file’s
DF_FILE_ALIAS attribute to decide what to do.

The default value of smart_filemode_state is false. You can set the state true in
individual data-dictionary subclasses, or even DDOs, but you should keep in mind that
smart filemode will not occur if any DDO participating in the save or delete has
smart_filemode_state false.

If you want all DSOs to employ smart filemode as the default, you may change the global
default setting in DFALLENT.PKG to:
DEFINE DEFAULT$SMART$FILEMODE$STATE FOR TRUE

If you do this, remember to re-pre-compile your dfallent package.


Refresh Mechanism
DDOs are designed to inform all connected data-entry objects about any change in the
DDO’s data. A change occurs anytime a DDO is asked to find, clear, save, or delete a
record. A data-server structure does this by sending the refresh message to all affected
DDOs. The refresh mechanism is used by the data-dictionary classes to ensure that
each DEO receives one and only one refresh message per data-dictionary operation
(e.g., find, clear, save, delete, superfind), regardless of the number of DDOs each DEO
is attached to. When a find is performed by a DDO, other DDOs may be required to
perform a find or possibly a clear. As a result, we often need to display items from some
files at the same time as clearing items from other files.

When a data-entry object receives a refresh message (a protected message sent from
DDOs to DEOs) it will display or clear data based on the refresh mode (see below) and
the status of the last file operation (record was found, record was cleared, no change).
Based on these conditions, the DEO will send itself the entry_clear and/or the
entry_display messages. In general, refresh is defined as a procedure with one
argument, the mode, which signifies the event or operation that generated this refresh
message, as follows:

procedure refresh integer mode

The modes are described below.

-81-
DataFlex 3.2 Data Dictionary Guide

mode_clear
This mode is used only for data-entry objects (DEOs) attached to the DDO that was the
"origin" of a clear operation, i.e., the DDO that received the original clear request or
message as a result of a user pressing kclear. All other DDOs send their DEOs the
refresh message passing mode_find_or_clear_set.

mode_find_or_clear_set
This mode is used for DEOs attached to DSOs that have found and/or cleared records in
response to a user's find request (kfind, kfind_next, ksuperfind, etc) or in response to
another DDO’s find or clear.

mode_clear_all
This mode is used for DEOs attached to any DDO that participated in a clear_all
operation.

mode_delete
This mode is used for DEOs attached to any DDO that performed a successful deletion.
DDOs that were merely updated as the result of a deletion use mode_find_or_clear_set.

mode_save
This mode is used for DEOs that are attached to a DDO involved in a successful save
operation.

The action of refresh is to send entry_clear 1 followed by entry_display 0 0; i.e., refresh


performs a simultaneous clear and display operation.

The refresh message is implemented in the base class entry and also in the classes
data_list and dbEdit.

The Is_file_included Command

The entry_update, entry_display, and entry_clear messages all affect the fields that
were just affected by the last database operation. When augmenting these messages,
typically, the parameters passed will just be forwarded without alteration. However, in
some special cases, it may be necessary to determine which files were (or are to be)
affected.

The is_file_included command is provided for this purpose. It accepts two arguments:
the first is the number of the file to check, and the second argument must be 1 or 0,
-82-
DataFlex 3.2 Data Dictionary Guide

depending on the whether you want to know if the last database operation performed a
clear (0) or a find (1) on the file in question. This command resets the found indicator to
true if the file was/is included, false if not.

Example:

procedure entry_display integer file# integer display_all


local integer dispv
forward send entry_display file# display_all
// we want to know if vehicle file was cleared, found, or unchanged
is_file_included vehicle.file_number 1 // Was record found?
if [found] Begin // Yes, it was found. Perform
: // find customization
end
else begin // either cleared or not affected
is_file_included vehicle.file_number 0 // Was buffer cleared?
if [found] Begin // Yes, it was cleared. Perform
: // clear customization
end
else ... // If here, file was neither found or cleared
end
end_procedure

Again, it is not expected that you will need to use this command in typical programs.
The Data-Dictionary Operation Integers
Two global integers are maintained during data-dictionary operations: operation_origin
and operation_mode. These values are maintained by the system and should not be
changed. They can be queried and may provide valuable information about a database
operation.

When a major data-dictionary operation begins, the DDO will check operation_mode to
make sure that there is no other data-server operation currently in process. Since data-
server operations are not reentrant, the value of operation_mode must be
mode_waiting. Operation_mode is set based on the type of operation (clearing, finding,
saving, deleting). When the operation is complete, operation_mode is again restored to
mode_waiting. The clear and clear-all operations set it to mode_clearing. The find and
superfind operations set it to mode_finding. The save operation sets it to mode_saving,
and the delete operation sets it to mode_deleting.
In advanced applications, you can use the value of operation_mode to perform custom
augmentations. For example, you may discover that you need two backout behaviors,
one for saving and one for deleting:

Procedure Backout
if operation_mode eq mode_deleting Begin
: // custom backout for deleting

-83-
DataFlex 3.2 Data Dictionary Guide

end
else Begin // if not deleting, it must be saving
: // custom backout for saving
end
end_procedure

In the following example, we will use operation_mode inside the


operation_not_allowed procedure to determine if the error being passed is a save or a
delete error:
procedure operation_not_allowed integer err#
if operation_mode eq mode_saving ;
error err# "- Save Error"
else if operation_mode eq mode_deleting ;
error err# "- Delete Error"
else ;
forward send operation_not_allowed err#
end_procedure

The operation_origin indicates which DDO initiated the data-dictionary operation. It


contains the object ID of the originating DDO. The values of operation_mode and
operation_origin are always set at the same time. Operation_origin is 0 when no data-
server operation is in progress.

Operation_origin was created for the sole purpose of giving the developer more
information about a data-server operation.

In this example, we will use operation_origin to make sure that a new record is never
saved when that new record is being used as a parent (i.e., the record is not the
main_file of the DDO that received the request_save message):

Function Validate_Save returns integer


Local integer rval crec
Get current_Record to crec // if 0, it is new
If (crec= 0 AND Operation_Origin <>Current_Object) ;
Error 304 "Can't save this parent record at this time."
// we only get here if everything is still ok
forward get validate_save to rval
function_Return rval
end_function

Another application of operation_origin and operation_mode might be found in an


error-tracking system. In a typical application, all errors are sent to a single error handler
(object). You might decide that you wish to trap and record DDO save and delete errors.
Inside your error object, you could determine if the error was a data-dictionary error
(check that operation_mode is not equal to mode_waiting), what the data-server

-84-
DataFlex 3.2 Data Dictionary Guide

operation was (again look at operation_mode), and which DDO this occurred at (look at
operation_origin).

Auto-fill and Data Dictionaries


DDOs maintain a property named auto_fill_state. This property is not normally altered by
programmers, but is maintained by the DDO according to whether or not a grid is being
used as one of its container data-entry objects. When a grid is one of the DEOs that use a
given DDO, the auto_fill_state of that DDO is defaulted to true. This causes the DDO to
refind records that satisfy the constraints (if any), causing the grid to constantly display all
of the records that satisfy the constraints.

All data-entry objects also support this same property: grids default it to true, which
causes its server to default to true as well, while all other data-entry objects use false as
the default. If you were to change the auto_fill_state of a form to true, it would cause its
DDO to auto-fill as well, and attempt to find the first record that satisfied the constraints.
This means that the entry form would always show data whenever possible, just like a
grid.

The following are messages and properties that can be sent to and used with DDOs to
control and perform specific parts of data-dictionary behaviors:
Saving and Deleting
You can send request_save or request_delete to the DDO to mimic the pressing of the
Save key (F2) (excluding the item-validation, -verification, and -auto-clear operations) or
the Delete key (Shift+F2) (excluding the verification and auto-clear operations). If you
wish to change the default action of the save and delete operations for a given data-entry
object, you can override the request_save and/or request_delete messages in that
object so that it sends request_save and/or request_delete to the appropriate DDO. The
no_delete_state and read_only filemode also affect whether these messages will
actually perform. Deleting is also affected by the value of cascade_delete_state.
Validation and Constraints
The request_validate message can be sent to cause the validation of the items in the
DDO’s data-entry objects. This type of validation is automatically performed by the DDO
as part of the save operation. The rebuild_constraints message should be sent to re-
initialize the constraints if they are altered after being initialized the first time. You should
also send some sort of find message afterward to ensure that the current record of the
DDO satisfies the new constraints.
Item Validation
Item validation in DEOs occurs under two conditions: navigation and saving.
-85-
DataFlex 3.2 Data Dictionary Guide

A property is mixed into dbForms and dbGrids (from the validate_mixin class) named
validate_mode. It can be set to any of these modes: validate_default,
validate_on_save, and validate_on_save_next. Forms default to validate_default.
Grids default to validate_on_save_next, which limits item validation to line-exiting (Next)
navigation and saves. This helps grid navigation by suppressing spurious validation errors
that otherwise occur during data entry in rows.

Item-Navigation Validation

When users navigate forward in a grid, item validation occurs. By far the most-common
occurrence of this validation is when the cursor moves forward one item (by pressing
Tab). If users move forward several items in a grid or a form, item validation occurs for
each item between the current item and the new item. If they navigate directly from Item 5
to Item 8 with the mouse, Items 5, 6, and 7 will be validated.

In backwards navigation in a form, item validation does not occur. Navigation between
objects also does not trigger item validation for all items. This means that it is possible to
navigate forward (between objects) without triggering item validation and at other times, to
trigger unwanted item validation.

Saving Validation

Before a DDO tries to save a record, it will first validate all appropriate items in all DEOs
that participate in the save. This means that all items get validated before a save occurs.
If any item validation fails, the save is stopped and the item that failed is made the current
item. The validation is triggered by the DDO sending the message validate_items to all
connected DEOs. The validate_items message sends the iValidate message to each
item in the DEO (or in the case of a grid, to each item in the row) individually.

Do not confuse this with the DDO validate_save function. The validations just described
occur before the save (and before any files are locked). The validate_save function, by
contrast, is called during a locked state just before the actual record save to check
database values that might have changed during entry of the record (often as a result of
the actions of other users).
A property named validate_all_items_state is provided to tell if an item validation is
being called as part of item navigation or saving. If this value is true, the item is being
validated as part of a save. If false, the item is being validated on item navigation.
Programming Item Validation for the Way It Is Used

In a 100%-event-driven system, the program makes no assumptions about what order


data will be entered in. Users should be allowed to enter data from top to bottom, bottom
-86-
DataFlex 3.2 Data Dictionary Guide

to top, or any other order. Where applications are in fact used this way, validation on
forward navigation does not really make sense. In fact, in this kind of environment,
validation during navigation probably makes no sense at all. In a 100%-event-driven
environment, all item validation should probably be processed during the save.

In non-event-driven usage, processing usually proceeds down a form (or across a grid)
one item at a time. If users navigate backwards, they are usually making corrections and
will eventually navigate forward again. In this kind of environment, item validation could be
provided only during forward navigation.

A real data-entry program is typically a mix of these two styles. While the system is
inherently 100% event-driven, most users use it in a non-event-driven way most of the
time. In other words, most usage of data-entry programs consists almost entirely of
forward item navigation (usually performed with Tab). Trying to take the best advantage of
item validation in this kind of environment is a challenge. While there currently exists no
perfect solution, DataFlex provides several validation modes, allowing you to better match
item validation to your applications and the ways in which they should be used.

The Validate_mode Property

The validate_mode property determines under what conditions item validation will occur.
The three modes are:

Validate_default This mode makes item validation work exactly as it normally does in
DataFlex. If the property object_validation is true (and it almost always is), validation
occurs during forward navigation within a DEO and during a save (when all items are
validated). If object_validation is false, item validation will not occur during navigation or
during a save. During a save, item validation is skipped for DEOs with object_validation
set false.
This is the most-intensive form of item validation. It works well with entry forms and is
therefore the default validate_mode for dbForm objects.

Note that item validation does not occur with all forward navigation. When users switch
forward to the next object, not all items between the old object's current_item up to the
new object's current_item are validated. Because of this, it is critical that all items get
validated during a save.
Validate_on_save When this mode is selected, item validation only occurs during a
save. This is the 100%-event-driven approach. This gives users the ability to enter data in
any order they wish. An invalid entry is not recognized until a save is attempted.

Validate_on_save_next This mode represents a compromise between the other two


modes. Item validation occurs during a save and during next message navigation. The
-87-
DataFlex 3.2 Data Dictionary Guide

next message is usually sent by the Tab key. This is the default validate_mode for the
Grid class, but you may also find that it works well for entry forms. Grids have a tendency
to produce unwanted validation errors during navigation to and from blank rows and
between objects. This mode seems to solve these problems.

Basically it acts like the validate_on_save mode (only validating during a save) with a
single concession to "procedural" data-entry (Tab produces a validate). This concession
gives you item validation during your most-common data-entry navigation while providing
complete flexibility for all other types of navigation. It seems to be a good compromise.

Object_validation and Validate_mode

In order for the validate_on_save and validate_on_save_next modes to work properly,


the object_validation property must be set to false. Setting validate_mode to either of
these modes will also set object_validation to false. If you set the validate_mode
property to validate_default, the object_validation property will get set to true. If, for
some reason, you need to change the validate_mode property to validate_default and
for some odd reason you want to set the object_validation property to false, you would
first have to set validate_mode and then set object_validation.
Controlling DDO Connections
A number of messages control how DDOs are linked to other DDOs and how data-entry
objects are linked to DDOs. Normally, these connections are maintained automatically. All
you need to know how to do is to use the set ddo_server (updating) and set server
(using) links. These messages are briefly discussed here and are presented in more
detail in the DataFlex Class Reference. This is a very technical discussion. You will
probably never need to use this information.

Connecting DDOs to DDOs

A client (child) DDO is attached to its server (parent) DDO with the DDO_server
message. This message is sent to the client DDO with the object ID of the server DDO as
its single parameter.

The detach_server message will remove a connection between a client DDO (which
receives this message) and a server DDO (whose object ID is passed as the single
parameter). None of the packages uses this method. The dynamic connecting and
disconnecting of client and server DDOs is considered a very advanced technique.

Connecting DEOs to DDOs

-88-
DataFlex 3.2 Data Dictionary Guide

When the server property of a DEO is set to the ID of the named DDO, the DEO knows
“who” its server is, but a two-way client-server link has not yet been created. At this point,
the DDO knows nothing about the DEO.

Whenever a DEO becomes active, it sends the add_user_interface message to its DSO
to notify it of its activation. During this process, a link is established between the DEO and
its server DDO and the DEO and any other DSOs whose data file might be referenced in
the DEO. These are referred to as watched servers. When the add_user_interface
message is sent to watched servers, an additional integer parameter (true) is passed
notifying the DDO that it is a watched server.
Now, whenever the DDO performs an operation that should affect its data-entry objects,
those objects will receive the appropriate message. When a DEO is deactivated with its
changed_state set to false, or when its changed_state is set to false when the object is
not active, the data-entry object sends remove_user_interface to the DDO to notify it
that it does not need to communicate with the DDO until it is activated again. The
remove_user_interface message is also sent to all watched servers, again passing an
additional parameter (true) indicating that a watched-server connection is being severed.

Note: This method of creating and removing data-entry links may change in the future.

Querying the Connection Lists of a DDO

DDOs maintain lists which allow them to keep track of server DDOs, client DDOs, client
DEOs, updating data files, and expected client-server files. Three lists contain database
files, two contain other DDOs, and one contains DEOs.

It is not expected that programmer access to these lists will be required in normal
applications. The messages may be of use to the advanced data-server developer (those
developers creating extended data-server subclasses). These messages also may prove
useful during the debugging process. Often program errors are a result of improper DDO-
to-DDO and DEO-to-DDO connections. These properties enable your program to check
these connections.

Data_set_server List
This is the list of all server DSOs. Servers are added to the list via the set ddo_server
message or via the attach_server message. Servers are removed from the list (rarely
done) with the detach_server message. The number of DSOs in the list can be queried
with the data_set_server_count function, and the ID of the DSO at a particular position
on the list is returned by the data_set_server function.

-89-
DataFlex 3.2 Data Dictionary Guide

Data_set_client List
This is the mirror image of the data-server list. Every time a client/server data-server link
is established, the client DDO adds the server object ID to its server list (see above) and
the server DDO adds the client object ID to its client list. The number of DDOs in the list
can be queried with the data_set_client_count function, and the ID of the DDO at a
particular position on the list is returned by the data_set_client message.

Data_set_user_interface List
This is the list of data-entry objects currently linked to the DDO. This link may be a server
link or a watched-server link. This link is not created with a set-server message. The
DDO does not add the user-interface object to its list until it receives an
add_user_interface message. Such connections can be broken with the
remove_user_interface message. The number of DEOs in the list can be queried with
the data_set_user_interface_count function, and the ID of the DEO at a particular
position on the list is returned by the data_set_user_interface message.

Client_file List
This is the list of child database files that relate to the main_file of the subject DDO (i.e.,
this is a list of all expected child files). This list is not built automatically, but with
add_client_file messages that you must program yourself. The list should contain all
child files that are related to this file. Currently this list is used to inhibit a delete if child
records exist. In the future this list will perform other tasks. Files can be removed from this
list with the remove_client_file message. The number of files in the list can be queried
with the child_file_count function, and the number of the file at a particular position on
the list can be queried with the child_file function. Child files are those files that contain a
record relating to the record to be deleted.

Server_file List
This is the list of files to which the main_file of the subject DDO should relate (i.e., this is
a list of all expected parent files). This list is not built automatically, but with
add_server_file messages that you must program yourself. The list has no specific
purpose at this time, but in that it probably will in the future, you would be well-advised to
create and maintain this list at least for your new DDOs starting right away. Files can be
removed from this list with the remove_server_file message. The number of files in the
list can be queried with the server_file_count function, and the number of the file at a
particular position on the list can be queried with the server_file function.

-90-
DataFlex 3.2 Data Dictionary Guide

Parent_file List
This is the list of database files named in the updating clause of the subject DDO’s
object-creation statement. This (non-recommended) connection is established with the
add_parent_file message and removed with the remove_parent_file message. The
number of files in this list may be queried with the parent_file_count function, and the
number of the file at a particular position in the list is returned by the parent_file function.

Sample Data-Dictionary Code


The following data-dictionary definitions are provided on disk with the Order sample
application. They are printed here to show actual usage of features described above.
Customer.dd
//DDB-FileStart
//DDB-HeaderStart

// File Name : CUSTOMER.DD


// Class Name: Customer_DataDictionary
// Revision : 2

Use Windows // Basic Definitions


Use DataDict // DataDictionary Class Definition
Use DDvalTbl // Validation Table Class Definitions

Open Customer
Open Orderhea
Open Ordsys

//DDB-HeaderEnd
//DDB-SelectionStart
//DDB/ ExternalSelectionList Customer_sl Customer.sl
Register_Object Customer_sl
//DDB-SelectionEnd

Class Customer_DataDictionary is a DataDictionary

Procedure Define_Fields
Forward Send Define_Fields
//DDB-DefineFieldStart

Set Main_File To Customer.File_Number


Set Cascade_Delete_State To FALSE

Set Foreign_Field_Options DD_KEYFIELD To DD_FINDREQ


Set Foreign_Field_Options DD_INDEXFIELD To DD_NOPUT
Set Foreign_Field_Options DD_DEFAULT To DD_DISPLAYONLY

-91-
DataFlex 3.2 Data Dictionary Guide

// Child (Client) file structure................


Send Add_Client_File Orderhea.File_Number

// External (System) file structure.............


Send Add_System_File Ordsys.File_Number DD_LOCK_ON_NEW_SAVE

Define_Auto_Increment Ordsys.Cust_Number To Customer.Number

// Field-based properties.......................

// Customer.Number
Set Field_Label_Long Field Customer.Number ;
To "Customer Number"
Set Field_Label_Short Field Customer.Number To "Number"
Set Field_Options Field Customer.Number ;
To DD_AUTOFIND DD_NOPUT
Set Field_Prompt_Object Field Customer.Number ;
To (Customer_sl(Current_Object))
Set Key_Field_State Field Customer.Number To TRUE
Set Status_Help Field Customer.Number ;
To "Customer Id Number (system assigned)."

// Customer.Name
Set Field_Label_Long Field Customer.Name ;
To "Customer Name"
Set Field_Label_Short Field Customer.Name ;
To "Customer Name"
Set Field_Prompt_Object Field Customer.Name ;
To (Customer_sl(Current_Object))
Set Status_Help Field Customer.Name ;
To "Customer/Company Name."

// Customer.Address
Set Field_Label_Long Field Customer.Address ;
To "Street Address"
Set Field_Label_Short Field Customer.Address To "Address"
Set Status_Help Field Customer.Address ;
To "Street Address."

// Customer.City
Set Status_Help Field Customer.City To "City Name."

// Customer.State
Set Field_Class_Name Field Customer.State To "dbComboForm"
Set Field_Label_Long Field Customer.State To "State"
Set Field_Label_Short Field Customer.State To "St."
Set Field_Options Field Customer.State To DD_CAPSLOCK
Set Field_Value_Check Field Customer.State ;
To "AK|AL|AR|AZ|CA|CO|CT|DE|FL|GA|HI|IA|ID|IL|IN|KS|KY|;
LA|MA|MD|ME|MI|MN|MO|MS|MT|NC|ND|NE|NH|NJ|NM|NV|NY|OH|OK|OR|PA|RI|SC|;
SD|TN|TX|UT|VA|VT|WA|WI|WV|WY|CN"
Set Status_Help Field Customer.State ;
To "Two-letter state ID."

-92-
DataFlex 3.2 Data Dictionary Guide

// Customer.Zip
Set Field_Label_Long Field Customer.Zip ;
To "Zip/Postal Code"
Set Field_Label_Short Field Customer.Zip To "Zip"
Set Field_Mask Field Customer.Zip To "#####-####"
Set Field_Mask_Type Field Customer.Zip To MASK_WINDOW
Set Status_Help Field Customer.Zip ;
To "Zip or Postal Code."

// Customer.Phone_Number
Set Field_Label_Long Field Customer.Phone_Number ;
To "Phone Number"
Set Field_Label_Short Field Customer.Phone_Number To "Phone"
Set Status_Help Field Customer.Phone_Number ;
To "Phone Number."

// Customer.Fax_Number
Set Field_Label_Long Field Customer.Fax_Number To "Fax Number"
Set Field_Label_Short Field Customer.Fax_Number To "Fax"
Set Status_Help Field Customer.Fax_Number ;
To "Fax Phone Number."

// Customer.Email_Address
Set Field_Label_Long Field Customer.Email_Address;
To "E-Mail Address"
Set Field_Label_Short Field Customer.Email_Address To "E-Mail"
Set Status_Help Field Customer.Email_Address;
To "E-mail Address (internet)."

// Customer.Credit_Limit
Set Field_Class_Name Field Customer.Credit_Limit To "dbSpinForm"
Set Field_Mask_Type Field Customer.Credit_Limit ;
To MASK_CURRENCY_WINDOW

// Customer.Purchases
//DDB/ Comment_Short Field Customer.Purchases ;
To "Total Orders. Maintained by OrderHea DD"
Set Field_Label_Long Field Customer.Purchases ;
To "Total Purchases"
Set Field_Label_Short Field Customer.Purchases To "Purchases"
Set Field_Mask_Type Field Customer.Purchases ;
To MASK_CURRENCY_WINDOW
Set Field_Options Field Customer.Purchases ;
To DD_DISPLAYONLY

// Customer.Balance
//DDB/ Comment_Short Field Customer.Balance ;
To "Maintained by Orderhea DD"
Set Field_Label_Long Field Customer.Balance To "Balance Due"
Set Field_Label_Short Field Customer.Balance To "Balance"
Set Field_Mask_Type Field Customer.Balance ;
To MASK_CURRENCY_WINDOW

-93-
DataFlex 3.2 Data Dictionary Guide

Set Field_Options Field Customer.Balance ;


To DD_DISPLAYONLY

// Customer.Comments
Set Status_Help Field Customer.Comments ;
To "Additional Comments and Notes."

//DDB-DefineFieldEnd
End_Procedure // Define_Fields

Procedure Field_defaults
//DDB-FieldDefaultStart
Set Field_Changed_Value Field Customer.State To "FL"
Set Field_Changed_Value Field Customer.Credit_Limit To 1000
//DDB-FieldDefaultEnd
End_Procedure

End_Class // Customer_DataDictionary

//DDB-Selection-pkg-Start
Use Customer.sl // Customer_sl
//DDB-Selection-pkg-End
//DDB-FileEnd

Vendor.dd
//DDB-FileStart
//DDB-HeaderStart

// File Name : VENDOR.DD


// Class Name: Vendor_DataDictionary
// Revision : 2

Use Windows // Basic Definitions


Use DataDict // DataDictionary Class Definition
Use DDvalTbl // Validation Table Class Definitions

Open Vendor
Open Invt
Open Ordsys

//DDB-HeaderEnd
//DDB-SelectionStart
//DDB/ ExternalSelectionList Vendor_sl Vendor.sl
Register_Object Vendor_sl
//DDB-SelectionEnd

Class Vendor_DataDictionary is a DataDictionary

Procedure Define_Fields
Forward Send Define_Fields
//DDB-DefineFieldStart

-94-
DataFlex 3.2 Data Dictionary Guide

Set Main_File To Vendor.File_Number


Set Cascade_Delete_State To FALSE

Set Foreign_Field_Options DD_KEYFIELD To DD_FINDREQ


Set Foreign_Field_Options DD_INDEXFIELD To DD_NOPUT
Set Foreign_Field_Options DD_DEFAULT To DD_DISPLAYONLY

// Child (Client) file structure................


Send Add_Client_File Invt.File_Number

// External (System) file structure.............


Send Add_System_File Ordsys.File_Number DD_LOCK_ON_NEW_SAVE

Define_Auto_Increment Ordsys.Vendor_Number To Vendor.Id

// Field-based properties.......................

// Vendor.Id
Set Field_Label_Long Field Vendor.Id To "Vendor ID"
Set Field_Label_Short Field Vendor.Id To "Vndr ID"
Set Field_Options Field Vendor.Id ;
To DD_AUTOFIND DD_NOPUT
Set Field_Prompt_Object Field Vendor.Id ;
To (Vendor_sl(Current_Object))
Set Key_Field_State Field Vendor.Id To TRUE
Set Status_Help Field Vendor.Id ;
To "Vendor Id Number (system assigned)."

// Vendor.Name
Set Field_Label_Long Field Vendor.Name To "Vendor Name"
Set Field_Label_Short Field Vendor.Name To "Name"
Set Field_Prompt_Object Field Vendor.Name ;
To (Vendor_sl(Current_Object))
Set Status_Help Field Vendor.Name ;
To "Vendor Name."

// Vendor.Address
Set Field_Label_Long Field Vendor.Address ;
To "Street Address"
Set Field_Label_Short Field Vendor.Address ;
To "Address"
Set Status_Help Field Vendor.Address ;
To "Street Address."

// Vendor.City
Set Status_Help Field Vendor.City To "City Name."

// Vendor.State
Set Field_Class_Name Field Vendor.State To "dbComboForm"
Set Field_Label_Long Field Vendor.State To "State"
Set Field_Label_Short Field Vendor.State To "St."
Set Field_Options Field Vendor.State To DD_CAPSLOCK
Set Field_Value_Check Field Vendor.State ;

-95-
DataFlex 3.2 Data Dictionary Guide

To "AK|AL|AR|AZ|CA|CO|CT|DE|FL|GA|HI|IA|ID|IL|IN|KS|KY|LA;
|MA|MD|ME|MI|MN|MO|MS|MT|NC|ND|NE|NH|NJ|NM|NV|NY|OH|OK|;
OR|PA|RI|SC|SD|TN|TX|UT|VA|VT|WA|WI|WV|WY|CN"
Set Status_Help Field Vendor.State ;
To "Two letter state ID."

// Vendor.Zip
Set Field_Label_Long Field Vendor.Zip ;
To "Zip/Postal Code"
Set Field_Label_Short Field Vendor.Zip To "Zip"
Set Field_Mask Field Vendor.Zip To "#####-####"
Set Field_Mask_Type Field Vendor.Zip To MASK_WINDOW
Set Status_Help Field Vendor.Zip ;
To "Zip or Postal Code."

// Vendor.Phone_Number
Set Field_Label_Long Field Vendor.Phone_Number ;
To "Phone Number"
Set Field_Label_Short Field Vendor.Phone_Number To "Phone"
Set Status_Help Field Vendor.Phone_Number ;
To "Phone Number."

// Vendor.Fax_Number
Set Field_Label_Long Field Vendor.Fax_Number To "Fax Number"
Set Field_Label_Short Field Vendor.Fax_Number To "Fax"
Set Status_Help Field Vendor.Fax_Number ;
To "Fax Phone Number."

//DDB-DefineFieldEnd

End_Procedure // Define_Fields

// Field_Defaults:
// This procedure is used to establish default field values.

Procedure Field_Defaults
Forward Send Field_Defaults
//DDB-FieldDefaultStart
//DDB-FieldDefaultEnd
End_Procedure // Field_Defaults
End_Class // Vendor_DataDictionary

//DDB-Selection-pkg-Start
Use Vendor.sl // Vendor_sl
//DDB-Selection-pkg-End
//DDB-FileEnd

Salesp.dd
//DDB-FileStart
//DDB-HeaderStart

// File Name : SALESP.DD


-96-
DataFlex 3.2 Data Dictionary Guide

// Class Name: Salesp_DataDictionary


// Revision : 2

Use Windows // Basic Definitions


Use DataDict // DataDictionary Class Definition
Use DDvalTbl // Validation Table Class Definitions

Open Salesp
Open Orderhea

//DDB-HeaderEnd
//DDB-SelectionStart
//DDB/ ExternalSelectionList SalesP_sl SalesP.sl
Register_Object SalesP_sl
//DDB-SelectionEnd

Class Salesp_DataDictionary is a DataDictionary

Procedure Define_Fields
Forward Send Define_Fields
//DDB-DefineFieldStart

Set Main_File To Salesp.File_Number


Set Cascade_Delete_State To FALSE

Set Foreign_Field_Options DD_KEYFIELD To DD_NOPUT DD_FINDREQ


Set Foreign_Field_Options DD_INDEXFIELD To DD_NOPUT
Set Foreign_Field_Options DD_DEFAULT To DD_DISPLAYONLY

// Child (Client) file structure................


Send Add_Client_File Orderhea.File_Number

// Field-based properties.......................

// Salesp.Id
//DDB/ Comment_Short Field Salesp.Id ;
To "Unique U/C ascii Id. Assigned by user. "
Set Field_Label_Long Field Salesp.Id ;
To "Sales Person ID"
Set Field_Label_Short Field Salesp.Id To "ID"
Set Field_Options Field Salesp.Id ;
To DD_AUTOFIND DD_REQUIRED DD_CAPSLOCK
Set Field_Prompt_Object Field Salesp.Id ;
To (SalesP_sl(Current_Object))
Set Key_Field_State Field Salesp.Id To TRUE
Set Status_Help Field Salesp.Id ;
To "Sales person ID code - Upper case alpha"

// Salesp.Name
Set Field_Label_Long Field Salesp.Name ;
To "Sales Person Name"
Set Field_Label_Short Field Salesp.Name ;

-97-
DataFlex 3.2 Data Dictionary Guide

To "Sales Person Name"


Set Field_Prompt_Object Field Salesp.Name ;
To (SalesP_sl(Current_Object))
Set Status_Help Field Salesp.Name ;
To "Sales person name - first and last"

//DDB-DefineFieldEnd

End_Procedure // Define_Fields

// Field_Defaults:
// This procedure is used to establish default field values.

Procedure Field_Defaults
Forward Send Field_Defaults
//DDB-FieldDefaultStart
//DDB-FieldDefaultEnd
End_Procedure // Field_Defaults
End_Class // Salesp_DataDictionary

//DDB-Selection-pkg-Start
Use SalesP.sl // SalesP_sl
//DDB-Selection-pkg-End
//DDB-FileEnd

Invt.dd
//DDB-FileStart
//DDB-HeaderStart

// File Name : INVT.DD


// Class Name: Invt_DataDictionary
// Revision : 2

Use Windows // Basic Definitions


Use DataDict // DataDictionary Class Definition
Use DDvalTbl // Validation Table Class Definitions

Open Invt
Open Orderdtl
Open Vendor

//DDB-HeaderEnd
//DDB-SelectionStart
//DDB/ ExternalSelectionList Invt_sl Invt.sl
Register_Object Invt_sl
//DDB-SelectionEnd

Class Invt_DataDictionary is a DataDictionary

Procedure Define_Fields
Forward Send Define_Fields
//DDB-DefineFieldStart
-98-
DataFlex 3.2 Data Dictionary Guide

Set Main_File To Invt.File_Number


Set Cascade_Delete_State To FALSE

Set Foreign_Field_Options DD_KEYFIELD To DD_FINDREQ


Set Foreign_Field_Options DD_INDEXFIELD To DD_NOPUT
Set Foreign_Field_Options DD_DEFAULT To DD_DISPLAYONLY

// Child (Client) file structure................


Send Add_Client_File Orderdtl.File_Number

// Parent (Server) file structure...............


Send Add_Server_File Vendor.File_Number

// Field-based properties.......................

// Invt.Item_Id
Set Field_Label_Long Field Invt.Item_Id ;
To "Invt. Item ID"
Set Field_Label_Short Field Invt.Item_Id To "Item ID"
Set Field_Options Field Invt.Item_Id ;
To DD_AUTOFIND DD_CAPSLOCK
Set Field_Prompt_Object Field Invt.Item_Id ;
To (Invt_sl(Current_Object))
Set Key_Field_State Field Invt.Item_Id To TRUE
Set Status_Help Field Invt.Item_Id ;
To "Inventory Item Id - user defined identification"

// Invt.Description
Set Field_Label_Long Field Invt.Description ;
To "Invt. Description"
Set Field_Label_Short Field Invt.Description To "Description"
Set Status_Help Field Invt.Description ;
To "Inventory Part Desription"

// Invt.Vendor_Id
Set Field_Options Field Invt.Vendor_Id To DD_CAPSLOCK
Set Status_Help Field Invt.Vendor_Id ;
To "Vendor Number"

// Invt.Vendor_Part_Id
Set Status_Help Field Invt.Vendor_Part_Id ;
To "Vendor ID name for this item"

// Invt.Unit_Price
Set Field_Mask_Type Field Invt.Unit_Price ;
To MASK_CURRENCY_WINDOW
Set Field_Value_Range Field Invt.Unit_Price ;
To "0" "999999.99"
Set Status_Help Field Invt.Unit_Price ;
To "Retail unit price"

// Invt.On_Hand

-99-
DataFlex 3.2 Data Dictionary Guide

//DDB/ Comment_Short Field Invt.On_Hand ;


To "This is adjusted by the OrderDtl DD"
Set Field_Value_Range Field Invt.On_Hand ;
To "-999999" "999999"
Set Status_Help Field Invt.On_Hand ;
To "Units currently available"

//DDB-DefineFieldEnd
End_Procedure // Define_Fields

Function Validate_Save Returns integer


Local Integer rVal

Forward Get Validate_Save to rVal


If rval Function_return rval

If Invt.On_Hand lt 0 Begin
Error 300 "Insufficient Inventory stock"
Function_return 1
end
End_function // validate_save

// Field_Defaults:
// This procedure is used to establish default field values.

Procedure Field_Defaults
Forward Send Field_Defaults
//DDB-FieldDefaultStart
//DDB-FieldDefaultEnd
End_Procedure // Field_Defaults
End_Class // Invt_DataDictionary

//DDB-Selection-pkg-Start
Use Invt.sl // Invt_sl
//DDB-Selection-pkg-End
//DDB-FileEnd

OrderHea.dd
//DDB-FileStart
//DDB-HeaderStart

// File Name : ORDERHEA.DD


// Class Name: Orderhea_DataDictionary
// Revision : 2

Use Windows // Basic Definitions


Use DataDict // DataDictionary Class Definition
Use DDvalTbl // Validation Table Class Definitions

Open Orderhea
Open Orderdtl
Open Customer
-100-
DataFlex 3.2 Data Dictionary Guide

Open Salesp
Open Ordsys

//DDB-HeaderEnd
//DDB-ValidationStart

Register_Object Terms_table
Register_Object Ship_Table

Object Terms_table is a DescriptionValidationTable

Procedure Fill_List
Forward Send Fill_List
Send Add_Table_Value "NONE" "None established"
Send Add_Table_Value "COD" "COD"
Send Add_Table_Value "NET30" "Net 30"
Send Add_Table_Value "NET60" "Net 60"
Send Add_Table_Value "NET90" "Net 90"
Send Add_Table_Value "PREPAY" "Pre-payment required"
Send Add_Table_Value "PREPAY" "new terms"
End_Procedure // Fill_List
End_Object // Terms_table

Object Ship_Table is a CodeValidationTable


Set Type_Value To "SHIPPING"
Set Allow_Blank_State To TRUE
End_Object // Ship_Table
//DDB-ValidationEnd
//DDB-SelectionStart
//DDB/ ExternalSelectionList ORDERHEA_SL ORDERHEA.SL
Register_Object ORDERHEA_SL
//DDB-SelectionEnd

Class Orderhea_DataDictionary is a DataDictionary

Procedure Define_Fields
Forward Send Define_Fields
//DDB-DefineFieldStart

Set Main_File To Orderhea.File_Number

Set Foreign_Field_Options DD_KEYFIELD To DD_FINDREQ


Set Foreign_Field_Options DD_INDEXFIELD To DD_NOPUT
Set Foreign_Field_Options DD_DEFAULT To DD_DISPLAYONLY

// Child (Client) file structure................


Send Add_Client_File Orderdtl.File_Number

// Parent (Server) file structure...............


Send Add_Server_File Customer.File_Number
Send Add_Server_File Salesp.File_Number

// External (System) file structure.............

-101-
DataFlex 3.2 Data Dictionary Guide

Send Add_System_File Ordsys.File_Number DD_LOCK_ON_NEW_SAVE_DELETE

Define_Auto_Increment Ordsys.Order_Number To Orderhea.Order_Number

// Field-based properties.......................

// Orderhea.Order_Number
Set Field_Options Field Orderhea.Order_Number To DD_AUTOFIND
Set Field_Prompt_Object Field Orderhea.Order_Number ;
To (ORDERHEA_SL(Current_Object))
Set Key_Field_State Field Orderhea.Order_Number To TRUE
Set Status_Help Field Orderhea.Order_Number ;
To "Order Number - New orders are assigned numbers automatically"

// Orderhea.Customer_Number

// Orderhea.Order_Date
Set Field_Class_Name Field Orderhea.Order_Date ;
To "dbSpinForm"
Set Field_Entry_msg Field Orderhea.Order_Date ;
To Entry_Order_Date
Set Field_Mask_Type Field Orderhea.Order_Date ;
To MASK_DATE_WINDOW
Set Field_Prompt_Object Field Orderhea.Order_Date ;
To (ORDERHEA_SL(Current_Object))
Set Status_Help Field Orderhea.Order_Date ;
To "Date on which the order was placed"

// Orderhea.Terms
Set Field_Class_Name Field Orderhea.Terms To "dbComboForm"
Set Field_Value_Table Field Orderhea.Terms ;
To (Terms_table(Current_Object))
Set Status_Help Field Orderhea.Terms ;
To "Payment terms"

// Orderhea.Ship_Via
Set Field_Class_Name Field Orderhea.Ship_Via ;
To "dbComboForm"
Set Field_Value_Table Field Orderhea.Ship_Via ;
To (Ship_Table(Current_Object))
Set Status_Help Field Orderhea.Ship_Via ;
To "Shipping method"

// Orderhea.Ordered_By
//DDB/ Comment_Short Field Orderhea.Ordered_By ;
To "This is just a suggested list. No parent files support this"
Set Status_Help Field Orderhea.Ordered_By ;
To "Order placed by"

// Orderhea.Salesperson_Id
Set Field_Label_Long Field Orderhea.Salesperson_Id;
To "Sales Person Id"
Set Field_Label_Short Field Orderhea.Salesperson_Id;

-102-
DataFlex 3.2 Data Dictionary Guide

To "Sales ID"
Set Status_Help Field Orderhea.Salesperson_Id;
To "Sales Person who initiated the order"

// Orderhea.Order_Total
//DDB/ Comment_Short Field Orderhea.Order_Total ;
To "Maintained by the Orderdtl DD"
Set Field_Mask_Type Field Orderhea.Order_Total ;
To MASK_CURRENCY_WINDOW
Set Field_Options Field Orderhea.Order_Total ;
To DD_DISPLAYONLY

// Orderhea.Last_Detail_Num
//DDB/ Comment_Short Field Orderhea.Last_Detail_Num To "This is the "sys" counter for order detail.
Used/Mainted by OrderDtl DD"

//DDB-DefineFieldEnd
End_Procedure // Define_Fields

Procedure Field_Defaults
Forward Send Field_Defaults
//DDB-FieldDefaultStart
//DDB-FieldDefaultEnd
End_Procedure

// Add a default date if the field is blank


Procedure Entry_Order_Date Integer iField Date dDate
Local Integer Changed
Get Field_Changed_State iField to Changed
If ( Changed=0 AND dDate =0) Begin
SysDate4 dDate
Set Field_Default_Value iField to dDate
End
End_Procedure

Procedure Update
Forward Send Update
Send Adjust_Balances OrderHea.Order_Total
End_procedure

Procedure Backout
Forward Send Backout
Send Adjust_Balances (-OrderHea.Order_Total)
End_procedure

Procedure Adjust_Balances Number Amt


Add Amt to Customer.purchases
Add Amt to Customer.Balance
End_Procedure

Procedure Deleting
Forward Send Deleting
// see if we can decrement the order number in sys file...can only do

-103-
DataFlex 3.2 Data Dictionary Guide

// this if this is the newest order.


If OrderHea.Order_Number eq OrdSys.Order_Number Begin // if this is
Decrement OrdSys.Order_Number // the last number,
SaveRecord Ordsys // decrement and save.
End
End_Procedure

End_Class // Orderhea_DataDictionary

//DDB-Selection-pkg-Start
Use ORDERHEA.SL // ORDERHEA_SL
//DDB-Selection-pkg-End
//DDB-FileEnd

Orderdtl.dd
//DDB-FileStart
//DDB-HeaderStart

// File Name : ORDERDTL.DD


// Class Name: Orderdtl_DataDictionary
// Revision : 2

Use Windows // Basic Definitions


Use DataDict // DataDictionary Class Definition
Use DDvalTbl // Validation Table Class Definitions

Open Orderdtl
Open Orderhea
Open Invt

//DDB-HeaderEnd

Class Orderdtl_DataDictionary is a DataDictionary

Procedure Define_Fields
Forward Send Define_Fields
//DDB-DefineFieldStart

Set Main_File To Orderdtl.File_Number


Set Cascade_Delete_State To FALSE

Set Foreign_Field_Options DD_KEYFIELD To DD_FINDREQ


Set Foreign_Field_Options DD_INDEXFIELD To DD_NOPUT
Set Foreign_Field_Options DD_DEFAULT To DD_DISPLAYONLY

// Parent (Server) file structure...............


Send Add_Server_File Orderhea.File_Number
Send Add_Server_File Invt.File_Number

Define_Auto_Increment Orderhea.Last_Detail_Num To Orderdtl.Detail_Number

// Field-based properties.......................

-104-
DataFlex 3.2 Data Dictionary Guide

// Orderdtl.Order_Number
//DDB/ Comment_Short Field Orderdtl.Order_Number ;
To "Relates to OrderHea DD"
Set Field_Options Field Orderdtl.Order_Number To DD_NOPUT

// Orderdtl.Detail_Number
//DDB/ Comment_Short Field Orderdtl.Detail_Number ;
To "This is maintained internally and is normally not displayed"
Set Field_Options Field Orderdtl.Detail_Number To DD_NOPUT

// Orderdtl.Item_Id
//DDB/ Comment_Short Field Orderdtl.Item_Id ;
To "relates to Invt DD"

// Orderdtl.Qty_Ordered
Set Field_Exit_msg Field Orderdtl.Qty_Ordered ;
To Adjust_Display_Total
Set Field_Label_Long Field Orderdtl.Qty_Ordered ;
To "Quantity Ordered"
Set Field_Label_Short Field Orderdtl.Qty_Ordered To "Quantity"
Set Field_Mask_Type Field Orderdtl.Qty_Ordered ;
To MASK_NUMERIC_WINDOW
Set Status_Help Field Orderdtl.Qty_Ordered ;
To "Number of items ordered"

// Orderdtl.Price
//DDB/ Comment_Short Field Orderdtl.Price ;
To "Default is set from Invt. Can be adjusted for each order."
Set Field_Entry_msg Field Orderdtl.Price ;
To Entering_Price
Set Field_Exit_msg Field Orderdtl.Price ;
To Adjust_Display_Total
Set Field_Label_Long Field Orderdtl.Price ;
To "Price per Unit"
Set Field_Label_Short Field Orderdtl.Price To "Price"
Set Field_Mask_Type Field Orderdtl.Price ;
To MASK_CURRENCY_WINDOW
Set Status_Help Field Orderdtl.Price ;
To "Price per Unit"

// Orderdtl.Extended_Price
//DDB/ Comment_Short Field Orderdtl.Extended_Price;
To "system maintained: Ext Price = Qty * Price"
Set Field_Label_Long Field Orderdtl.Extended_Price;
To "Extended Price"
Set Field_Label_Short Field Orderdtl.Extended_Price;
To "Total"
Set Field_Mask_Type Field Orderdtl.Extended_Price;
To MASK_CURRENCY_WINDOW
Set Field_Options Field Orderdtl.Extended_Price;
To DD_DISPLAYONLY
Set Status_Help Field Orderdtl.Extended_Price;
To "Total extended price"

-105-
DataFlex 3.2 Data Dictionary Guide

//DDB-DefineFieldEnd
End_Procedure // Define_Fields

// Update and Backout need to adjust the Invt.On_Hand quantity,


// the dtl line's extended price and the OrderHea total. We will call
// the same procedure (Adjust_Balances) to insure that backout and
// update are inverses of each other.
// Note that Backout does not need to change the extended_price. This
// only gets changed as part of update.
Procedure Update
Forward Send Update
Move (OrderDtl.Price * OrderDtl.Qty_Ordered) to OrderDtl.Extended_Price
Send Adjust_Balances OrderDtl.Qty_Ordered OrderDtl.Extended_Price
End_Procedure

Procedure Backout
Forward Send Backout
Send Adjust_Balances (-OrderDtl.Qty_Ordered) (-OrderDtl.Extended_Price)
End_Procedure

// Called by Backout and Update passing the quantity


// and the extended price.
// Subtract quantity from Invt on-hand and
// add extended amnt to order total.
Procedure Adjust_Balances Number Qty Number Amt
Subtract Qty from Invt.On_Hand
Add Amt to Orderhea.Order_Total
End_Procedure

// when entering the price field we may wish to update the


// current field value with the standard unit price from the
// Invt file. Only do this if the current amount is zero. If non
// zero we assume the field is being edited (and we make no assumptions).

Character Mode Data Dictionary Class Reference


DataDictionary

Source
DATADICT.PKG
Purpose
To coordinate the use of database files by groups of data-entry objects and other data-
server objects. Where a group of data-entry objects shares a common database view,
they may do so through a shared data-server structure. In this class also, you can
prescribe a set of rules to be applied to all the records of a database file, without having to
repeat those rules in every data-entry object that addresses the file. The rules may specify
-106-
DataFlex 3.2 Data Dictionary Guide

what validations and other behaviors apply to its individual fields, and what
interdependencies exist between values in its fields and values in other data files. Using
this class allows for multi-level validations and error rollback, which can make it practically
impossible to damage the integrity of an application’s data.
This class should rarely, if ever, be instantiated itself. It should be used to create a
subclass for each file which will be used in an application. Rules and other attributes
common to all uses of the file should be specified in such subclasses. Rules and
attributes common only to a view may be further specified in instances of such
subclasses in such views.
Hierarchy
DataSet
└─DataDictionary

All documentation of the methods and properties of the superclass, dataSet, is presented
in this (dataDictionary) article.
Usage
use datadict
open file
use slist.sl // repeat for all required selection lists
class className is a DataDictionary
//Use the define_fields procedure to define all your business rules and
// expand it to set the following types of properties:
procedure define_fields
forward send define_fields
// define file properties
set main_file to file.file_number
// repeat for all required parent files
send add_server_file to pfile.file_number
// repeat for all required child files
send add_client_file to childFile.file_number
set cascade_delete_state to {true| false}
set protect_key_state to {true| false}
// apply masking (month names,currency characters,
// thousands separator, etc.)
set field_mask_type to fieldMaskType
set field_mask to tokenChars
// apply field options - these are used by entry items.
set field_options field file.field to fldopt1 […fldoptn]
// apply foreign-field options. While these can be set for individual
// fields, they are usually set for a field type: key, index, or default (no
-107-
DataFlex 3.2 Data Dictionary Guide

// index)
set foreign_field_options {field file.field| field_type} to;
fldopt1 […fldoptn]
// identify all fields that are part of the primary key
set key_field_state field file.field to true
// specify message to be sent when a field’s item is entered
set field_entry_msg field file.field to message
// specify message to be sent when a field’s item is exited
set field_exit_msg field file.field to message
// define validation rules and validation errors. Several options are
// available
set field_validate_msg field file.field to message
set field_value_range field file.field to lower upper
set field_value_check field file.field to list
set field_checkbox_values field file.field to true_value false_value
set field_value_table field file.field to object_id
set field_error field file.field to error_number error_text
// define prompt and zoom objects
set field_prompt_object field file.field to object_id
set field_zoom_object field file.field to object_id
// define a status help line for each field
set status_help field file.field to status_help_text
end_procedure

// define all field entry, exit, and validation procedures and functions set
// above, here
:
// define all DSO hook procedures and functions here
:
end_class

Argument Explanation
file The name of the DataDictionary subclass’s main (database) file.
slist.sl The name of a selection-list package file.
className The name of the DataDictionary subclass for file
Of Special Note
An object of this class (a DDO) manages transactions from the perspective of its
main_file. Data-entry views rely on these to manage their database files, and to ensure
that changes made through the data-entry objects are properly reflected in the database
files, while maintaining relational integrity.
-108-
DataFlex 3.2 Data Dictionary Guide

DDOs cooperate in interconnected structures to maintain a particular view of the


database. For example, using DDOs for customer, invoice, lineitem, and inventory, i.e.:
object inventory_dd is an inventory_dataDictionary
end_object

object customer_dd is a customer_dataDictionary


end_object

object invoice_dd is an invoice_dataDictionary


set ddo_server (customer_ds(current_object))
set ddo_server (inventory_ds(current_object))
end_object

We can enforce a view of the database having all customers, but having only invoices for the
current customer, only lineitems for the current invoice, and only inventory amounts for the
current lineitem. In addition, the effects of changes may be managed by the DDOs, and a
DDO may provide database services to one or more DEOs.

Terminology

DDOs may be made to update other DDOs by setting ddo_server for each DDO to be
updated naming each in the argument, and may be updated by other DDOs. DDOs that
update a DDO are referred to as its clients, and DDOs that are updated by a DDO are
referred to as its servers. Note that in this context, the term client refers to a DDO that
uses the services of another DDO, and not the Basic Class Client.
A DDO may have one main_file and a number of parent files which it updates whenever
users change the main_file. Such changes are made through DEOs to which the DDO
provides access to the database.

Finding

In the DataDictionary, dbForm, Text_window, and dbGrid classes, sends of


request_superfind to a DDO require Predefined Indicator err to be set to false
beforehand, in case an error other than Find past end of file or Find prior to beginning
of file is generated by the superfind.

Item Update

Update_dependent_items is sent as the last action of attach_deo_to_server for this


class. This coordinates the data values displayed by all DEOs attached to the data-server
structure.

-109-
DataFlex 3.2 Data Dictionary Guide

Constraints

Constraints are used to limit the records that are considered to be members of the data
set. Constraints are specified within a begin_constraints... end_constraints block. Each
DDO may have, at most, one constraint block, but within this block may be as complex a
set of constraints (including constraints whose values can be changed by users at run
time) as you may need.

A DDO's constraints not only affect finding of records, but clearing of records as well. In
general, any time a child-file DDO is cleared, its parent files’ DDO(s) will also be cleared if
and only if the child has no constraints that depend upon the parent. For example:
object parent1_dd is a parent1_dataDictionary
end_object

object parent2_dd is a parent2_dataDictionary


end_object

object child_dd is a child_dataDictionary


send attach_server (parent1_dd(current_object)) ;
(parent2_dd(current_object))
begin_constraints
constrain child relates to parent2
end_constraints
end_object

If child_dd is asked to clear (by one of its DEOs, etc.), the relates-to constraint from child to
parent2 will prevent parent2_dd from clearing, but parent1_dd will clear, since child_dd's
constraints do not depend on parent1.

Data-Entry Objects (DEOs)

DEOs may address DataDictionary objects in their server properties. If the server
property of a DEO is not defined, that DEO uses the server of its parent object. Zero,
one, or more DEOs may be connected to a DDO. Which DDO a particular DEO should
connect to depends on two things:

1. The fields used by the DEO. The DEO should be connected to the DDO for
the child-most file the DEO updates. For example, a DEO containing fields
from customer, invoice, and lineitem files should be connected to the DDO for the
lineitem file. If this DEO is connected instead to the invoice or customer DDO, no
lineitem fields will be displayed.
2. The actions desired for ksave_record, kclear and kdelete_record. These
keys cause a save, clear, or delete, respectively, of the current record for the
main_file of the DDO to which this DEO is connected. For example, a DEO
-110-
DataFlex 3.2 Data Dictionary Guide

containing fields from the customer and invoice files may be connected to the
DDO for the invoice file. In this case, ksave_record, kclear, and
kdelete_record will save, clear, or delete the Invoice file. This means that
customer records cannot be deleted through this DEO.

Creating New Records

You should define a procedure called creating to implement any effects of creating a new
record in the main file that you need. The creating procedure should only effect changes
which are different from update, since update is sent after creating automatically. An
example of a routine that should only apply to the creation of a new record is assigning a
unique ID from a field of a system file. Since creating is invoked while the database is
locked, do not use any command or message within this procedure that might cause the
workstation to stop and wait for input.

Deleting Records

You should define a procedure called deleting to implement any effects of deleting the
current main-file record that you need. The deleting procedure should only effect
changes which are different from backout, since backout is sent after deleting
automatically. An example of a routine that should only apply to the deletion of a record is
releasing a unique ID from an ID database for re-use by a subsequent new record. Since
deleting is invoked while the database is locked, do not use any command or message
within this procedure that might cause the workstation to stop and wait for user input.

Update/Backout

You should define procedures called update and backout, respectively, to implement any
effects of changes to records in the main file that you need. Both procedures should effect
changes only to directly related files. Update should calculate the effects of a record’s
new values, while backout should remove the current record's effects. An example of a
routine that should apply to the saving or deletion of a record is incrementing or
decrementing counters or totals. Since these procedures are invoked while the database
is locked, do not use any command or message within these procedures that might cause
the workstation to stop and wait for user input.

Validate_save/Validate_delete

You should define functions called validate_save and validate_delete to check for
conditions that must be satisfied before the current main-file record may be saved or

-111-
DataFlex 3.2 Data Dictionary Guide

deleted. Both functions should return a zero (0) if all conditions are satisfied, else they
should return a non-zero or generate an error to prevent the save or delete from
happening. These functions are intended for the purposes of maintaining relational
integrity and enforcing business rules, not verifying user input (see verify_save and
verify_delete messages of data-entry objects).

Error Reporting

In a data dictionary, your program can generate errors either by using the error command
or sending the messages field_error or operation_not_allowed (both of these
messages eventually generate the error command). The messages display more error
information than is displayed by the command used directly. The file number and name,
and (if appropriate) field number and name will be displayed as part of the error
information. All standard validation errors generated by this object use the messages. You
should use the messages rather than the command in your custom validation procedures.

Error Reporting During Save and Delete


The reporting of errors that occur during a save or delete operation on this object is
delayed until after the database has been unlocked. This is to prevent the error
notification from waiting for user input while the database is locked (this would prevent
others from using the locked data).

Modifying Error and Other Texts


This class uses an include file, DD_TEXT.INC, to provide error and other texts for
validation errors and the like. You can modify, replace, or even extend, the texts in this file
to suit the needs of your application and/or locale.

Operation_mode

The global integer operation_mode holds the status code of the current data-dictionary
structure. This integer has the value of mode_waiting when all DDOs are idle, of
mode_finding, mode_clearing, mode_creating, mode_saving, or mode_deleting
when not idle, or of mode_aborting when undoing the effects of an invalid save. Please
note that your update and backout procedures may need to provide code which is only
executed when undoing some effect of a save, i.e., deleting records from a log file.
Do not change the value of operation_mode—it is maintained by the runtime.

Entry_permissive_state

-112-
DataFlex 3.2 Data Dictionary Guide

This flag, if true, allows parent records of the main file to be changed in fields by which
records in child files relate to the parent-file record (reattaching main-file records to
different parent records, or perhaps to none). If false, parent/child record attachments
may not be altered (functions like ent$permissive in DataFlex Revision 2.3). Note that its
default value is true.

Read_only_state

This flag, if true, prevents any updating or deleting from occurring in this DataSet.

Field Validation

Validation rules may be applied to every field in a data file. This is done for the general
case by creating validation functions and assigning these functions to a field by setting the
field_validate_msg. Since these validation functions are code-based, they can represent
the most-complex validation rules.
Because they are used so commonly, the following four types of special-purpose
validations are supported: field_value_range, field_value_check,
field_checkbox_values, and field_value_table. Field_value_range allows you to
specify a field-value minimum and maximum range (e.g., set field_value_range field
order.qty to 0 100). Field_value_check allows you to specify a value from a delimited
string (e.g., set field_value_check file customer.state to “CA|MI|TX” ).
Field_checkbox_values allows you to define two checkbox values (e.g., set
field_checkbox_values file customer.active to “Y” “N”). Field_value_table enables you to
designate an object of class validationTable, DescriptionValidationTable,
FileValidationTable, or CodeValidationTable to contain or provide access to the
validation values.

By designating an object of Class ValidationList as a field’s field_prompt_object, you


can present the validation values for selection from the ValidationList object. By default,
the object will contain the values of the field as they exist in the database. The object can
display description-field values for code fields, and can be configured in other ways
described in the article on that class. But in order to obtain all the default behaviors, all
that is necessary is to name the object as the field_prompt_object, and declare the
object in the following form:
object myFieldValidate is a ValidationList
end_object

Field validation is triggered by every save. Normally these field validations also are
triggered by data-entry navigation. This can be controlled so that field validation is
triggered only by a save; by a save or “next” item navigation; or by a save and any
-113-
DataFlex 3.2 Data Dictionary Guide

forward navigation. Field validation is triggered for all files participating in the save or
delete. Even if a field is not represented in a data-entry object, it will still get validated
before a save. Field validation cannot be used on text or binary fields. Special properties
support key-field validation. By “protecting” key fields, you can make it impossible to
change an existing key field.

Data-Dictionary-Structure Validations

Before a program performs its first save or delete in a data-dictionary structure, the entire
structure is validated to make sure that it is complete. If the validation fails, the database
change is canceled. This protects against design errors. By default, this check only
occurs once in a session (since data-server structures tend to be static). This can be
changed to make this check occur for every save/delete, or to never occur. In the data-
set classes, you define a list of all expected parent (server) and child (client) files. This list
is compared to the actual data-server structure to ensure structural integrity. These
validations all occur during an unlocked state.
Certain files should be connected to the data-dictionary structure for which you have no
reason to create a data-dictionary subclass and object. A prime example is a system file
containing a counter either for census purposes or for the purpose of assigning unique
identification keys. Such files can be added to the structure with the add_system_file
message. If necessary, they can also be removed with the remove_system_file
message.

Two other (non-structural) validation functions, validate_save and validate_delete, occur


in a locked state right before the save or delete database operation is to actually occur.
This provides a final safety net to make sure that all data is mutually consistent. If any
type of error occurs during a save or delete operation, the file and field on which the error
occurred is reported, and the entire transaction is rolled back to its prior state. This
ensures that any unexpected errors (duplicate records, read-only files, values out of
range) will be trapped.

Normally, all fields in all files that participate in a save are validated. This includes fields
that aren’t displayed in the current view and all fields in all ancestor files. In almost all
cases, this level of data protection is desired and is a powerful feature of the data
dictionary. In rare cases, you may wish to select lower levels of validation protection. The
property validate_foreign_file_state determines if field validation should be applied to
foreign (ancestor) files. Normally you want this level of valdiation, so its default value is
true. Setting its value to false will skip field validation when the file is used as a parent file
in your DSO structure. It will also suppress validation in all that file’s ancestor files. The
property validate_deos_only_state specifies whether field-level validation should be
applied to all fields or only to fields displayed in the view. When reset to true, field
validation will only occur on fields that have a user-interface component. This would make
-114-
DataFlex 3.2 Data Dictionary Guide

your DataDictionarys behave more like DataSets, where validation was only applied to
visual entry items.

Setting these properties away from their defaults essentially defeats full field validation
and potentially compromises data integrity. They should only be used under carefully
controlled circumstances. Why would you wish to set these properties away from their
defaults? When converting applications from data sets to data dictionaries, you may find
that the extra level of field validations is generating errors in existing records. In such a
case, you may need to disable some validations until these problems can be corrected. In
other cases, you may find that limiting validations results in worthwhile performance
gains.

One final word of warning. Do not use these properties as short-cut solutions to bad
database design. Special conditional validation rules can be programmed directly into
your validation routines. For example, you could build a validation routine that only applies
a field validation to new records (check the record’s status with the current_record
property) or you could create validation routines that selectively skip certain fields when
they are foreign (the operation_origin global integer tells you which DSO started the
save). Rather than breaking a rule, attempt to define this rule change as part of your rule
set. In the long run, you will have a better, more-robust application.

Synchronized Local Record Buffers

Local copies of record-buffer values are stored in each DDO. These values are accessed
with the get/set field_current_value and get/set field_changed_state messages.
Values of parent-file fields can be accessed with the get/set file_field_current_value
and get/set file_field_changed_state messages. Data-entry objects (DEOs) are
synchronized so that changes in a DEO item update the local record buffer. Field values
can be changed directly in the DSO. Changes in the local record buffer (with set
field_current_value) will update connected DEO items. Field values may be changed
(and saved) even if this value has no visual representation in a data-entry object. The
DSO manages dependent-item updates within a view. A change in a file/field value in one
DEO will be reflected in all other DEOs with the same file/field. Because all changed
values are stored in the DSO, the DSO never needs to access information from its DEOs.

Field Properties

Entry_item options support in DataDictionary: Most options formerly specified in


French braces ({…}) in entry_item statements may be assigned in the DataDictionary
subclass. All item options (capslock, required, retain, autofind, noput, displayonly,
etc.) can be specified directly in the DataDictionary using the field_options property.

-115-
DataFlex 3.2 Data Dictionary Guide

Check=, range=, item_entry, item_exit, item_validate, item_prompt, and item_zoom


settings are supported by special messages. All these options are applied to the DEO
items by the DataDictionary as required for the field in question.
Foreign-field properties: A DEO usually contains items for fields in its server file (the
main file of the DSO it is using) or one or more of the main file’s parent (ancestor) files.
These ancestor files are referred to as “foreign” files. Often fields require different
properties according to whether they are in the main or a foreign file. Foreign-field
properties handle this.

Foreign-field properties may be specified for any field or type of field. Most often you will
find that you wish to add a noput, displayonly, or findreq property to a foreign field. This
is handled with the foreign_options property.

Foreign-field options are often most-conveniently applied to classes of fields according to


the way they are used. There are key fields, index fields, and fields that are neither of
these. For example, key fields might require a noput and findreq, index fields might
require only a noput, and default fields might require a displayonly. You can set
foreign_field_options for any of these classes. Any properties thus applied to a class
are added to any properties that may have been applied to any foreign field individually.
Field properties may also be applied, or suspended, at the DEO level.

Field Masking

Using the field_mask_type property, and/or the associated field_mask property, you can
restrict data entry to a field to a defined pattern of numbers, letters, and punctuation
marks, and provide displays of field values complying with such pattern with the addition,
if desired, of additional literal characters and/or translations of numeric values to names
and abbreviations such as days of the week or months of the year.

The default currency string always delivers the local currency symbol as it is set in the
Windows operating system at the using site.

Translating from numbers to names is sensitive to the Windows locale settings at using
sites. Where you may have seen Januar as the first month on your system, users with
English-language locale settings will see January, while those with French-language
locale settings will see Janvier. Attributes such as date-component order are under the
control of the masking you specify for display, and under the control of local environment
settings for data entry (except that DataFlex always requires four-digit entries for years).
Data entry is done numerically even in fields that are masked for display of names of
months, days, etc.

-116-
DataFlex 3.2 Data Dictionary Guide

Status-Help Support

The set status_help message allows you to define status help for each field. If status
help is not defined for the item in the DEO, the help line for the field will be fetched from
the DataDictionary.

Default-Values Support

The field_defaults procedure is provided to support the setting of default values after a
clear. You may set any field value, which will then be reflected in the DEOs and will get
saved with the new record. Because the setting of defaults is coded in a procedure, you
may create complex rules for the setting of defaults. The setting of a default is not
recognized as a data change by the DataDictionary; therefore the setting of defaults will
not generate a “data-loss” error message. Defaults may also be set upon entry of an entry
item by setting the field_entry_msg and field_default_value properties.

Optional Cascade-Delete Support

The cascade_delete_state property controls how a delete affects records in child files. If
the property is true, all child (and descendant) records will be deleted. If it is false, the
data set will disallow the deleting of a record if child records exist.

Full Custom Control of Saves and Deletes

All standard DataSet “hook” procedures are available, providing you with full control of the
entire save and delete process. These include the basic hooks: create, update,
backout, and delete; and the advanced hooks: relate_main_file, attach_main_file,
and save_main_file.

When you wish to assign it a unique key, or identifier, from a system file to new records
when they are saved, you can use the define_auto_increment command within the
define_fields procedure.
define_auto_increment ordsys.cust# to customer.number

In this example, Field cust# in System File ordsys is designated to increment and provide a
value to Field number in Main File customer whenever a new record is saved in customer. Only
one field in a given main file can be addressed by define_auto_increment.

Data-Server Classes Are Code-based

-117-
DataFlex 3.2 Data Dictionary Guide

Because the data-server classes are code-based, you are not limited to a predefined set
of rules and validations. This allows you to create file validations, field validations and field
defaults of any degree of complexity. Because the data-server classes are class-based,
these rules can be modified though sub-classing or though customized object coding.
This allows you to make the rules; modify the rules and, when absolutely necessary,
break the rules.

Optimization

The DataDictionary class employs “smart-file-mode” technology, ensuring that only the
files that actually participate in a save or delete operation are actually locked and reread.
This can provide significant speed improvements.

Full Character-Mode / Windows Compatibility

The data-server classes used by the DataFlex Windows and character-mode versions are
identical. Because code is removed from the DEOs to the DSOs, the compatibility
between the two products is increased.

Many of this class’s properties are coded as Procedure-Set/Function pairs, but these are
not documented in the “Procedures and Functions” section. They are documented, and
used, the same as real properties.

Properties

Normal Interface

auto_fill_state — boolean — true | false

If the value of this property is true, this object will attempt to find the first record in its
defined set when it becomes in-use (see in_use_state, below). If any attached DEO has
its auto_fill_state set true, this object’s auto_fill_state will also be true until all such
DEOs have been detached from this object by use of the remove_user_interface
message.

cascade_delete_state — boolean — true | false

In its default state, this property provides for the deletion of all records in the main_files of
DSOs updated by this object that relate to the main_file record of this object that is being
deleted. If you do not desire this behavior in a DSO, set this property false and send
-118-
DataFlex 3.2 Data Dictionary Guide

add_client_file messages to name each relating child file for which you would want the
delete cancelled in the event that a record exists in the child file that relates to the record
for which deletion is requested. Then deletions will be allowed only of records having no
relating child records in the named files. All named files must be open; if not, the delete
will fail.

changed_state — boolean — true | false

If the value of this property is true, one of the DEOs attached to this object has changed,
and/or a parent record relationship has been changed. Set by DEOs.

constrain_file — integer — file_number

This property holds the number of the file according to whose current record values,
selection in the main file is to be constrained. Used by constrain procedure.

ddo_server — integer — objectID

This property holds the objectID of this object’s server dataDictionary. This object may
have several such servers, and this property is in fact an array, which may hold as many
server objectIDs as it is set to hold. Only one objectID may be given with each set
statement.

entry_permissive_state — boolean — true | false

If the value of this property is true, changing of parent record relationships is permitted. If
the value of this property is false, changing of parent record relationships is not permitted.
For example, suppose we have two files, Parent and Child, where Child relates to Parent.
If our database has records Parent-1, Parent-2, and Child-1, where Child-1 relates to
Parent-1, we have two possible situations:

1. If entry_permissive_state is true, we may find Parent-2 and save the Child-


1 record, thus altering the Parent record related to by the Child-1 record from
Parent-1 to Parent-2.
2. If entry_permissive_state is false, finding Parent-2 would cause the child
record buffer to either find a Child record relating to Parent-2 or clear. In
effect, if entry_permissive_state is false, finds on parent files are treated
as superfinds. Since the parent records of this object’s main_file may be
owned by its servers, objects of this class respect the
entry_permissive_state of their clients. If this object is attached to a client
-119-
DataFlex 3.2 Data Dictionary Guide

whose entry_permissive_state is false, all finds on the main_file of this


object become superfinds.

error_report_mode — integer — DD_error_report | DD_error_no_report

This property determines how errors are generated through the messages
operation_not_allowed and data_set_error. When set to DD_error_report (the default)
errors are declared and handled by the DataFlex error system. If set to
DD_error_no_report, the error is not reported, but the err indicator is set, indicating that
an error did occur. Use of this property can be expanded to support other types of error
reporting (log to error file, etc.).
set error_report_mode to DD_error_no_report

field_changed_state integer iField — boolean — true | false

Gets/sets field_changed_state of the passed field. Returns true when a field has been
changed since this object was last cleared or a record found in it. Sets
field_changed_state only if change_disabled_state is false.
Get Field_Changed_State field file.field to var

field_changed_value integer iField — string

This property is a combination of the Field_current_value and Field_Changed_State


properties. It sets the field_current_value and sets field_changed_state to true. This
property can only be set; it cannot be getted, although the two component properties can
be.

Example:
Procedure Field_defaults
Set Field_Changed_Value field customer.state to "CA"
End_Procedure

field_checkbox_value integer iField boolean bTrue — string — value

This property returns the value for iField that stands for the value (true or false) of bTrue.
Begin_Constraints
local integer bStatus
local string sStatus
Get Active_only_State to bStatus
-120-
DataFlex 3.2 Data Dictionary Guide

If bStatus Begin
Get Field_Checkbox_Value Field Customer.Status TRUE to sStatus
Constrain customer.Status eq sStatus
end
End_Constraints

field_checkbox_values integer iField — string string— trueValue falseValue

The Field_Checkbox_Values property is used to define a field’s items as checkbox


items (an item only having two possible values) and defining what the valid values are.
The first of these is referred to arbitrarily as the “true” value and the second, as “false,”
although there might be no intrinsic meaning to these terms so used. The user interface
need not give any indication of this convention. Once defined, the field will be validated
against the two values. If a DEO attached to this field is a checkbox object, the checkbox
will be set based on the value in the field. The validation error text returned by items
subject to this property automatically discloses both the nature of the error and the two
acceptable values.
Set field_Checkbox_Values field customer.status to “A” “I”

field_current_value integer iField — string — value

This allows you to get or set the current value of a field. If field_current_value is set, all
data-entry items that use this file and field value will be updated. Note that this gets and
sets the local record buffer in the DSO. It is not accessing the actual file buffer.

field_default_value integer iField — string — value

This property sets a default value. It sets the field value without setting the DSO's
Changed_State. This is used to set defaults inside field_entry_msg messages.

field_entry_msg integer iField — integer — msg_ID

Sets the ID of the message to be sent when the cursor enters an item for iField.

field_error integer iField — integer string — error_num error_text

This sets a specific error number and text for iField. This error and text will be passed with
data_set_error when any of the special field validations (field_value_range,
field_value_check, field_checkbox_values or field_value_table) fails.

-121-
DataFlex 3.2 Data Dictionary Guide

If iField is passed as -1, the error number and text will apply to every field in the file for
which this property is not separately (specifically) set. This property can only be set; it
cannot be getted, but the error number can be getted with the field_error_number
function, and the error text with the field_error_message function.

field_exit_msg integer iField — integer — msg_ID

Sets the ID of the message to be sent when the cursor exits an item for iField.

field_mask integer iField — string — token_characters

This property provides the token characters for the mask for item_num. Any characters
provided in this property for any mask type (defined in the field_mask_type property) for
which they are not token characters will be repeated in the displayed values literally.
Token characters can be displayed literally by preceding each with a backslash (\).
The token characters for field_mask_types mask_numeric_window and
mask_currency_window are:

, comma inserts local thousands’ separator every three places to the left of
the decimal
. period is replaced with the local decimal indicator
; semi-colon comes after format for positive quantities, before format for
negative numbers
# no digit or one digit
* any number of digits, including none
0 one digit, or a 0 (zero)

The token characters for field_mask_type mask_window are:

# any numeric digit (0-9)


@ any alphabetic character
! any punctuation character
* any single printable character

The token characters for field_mask_type mask_date_window are:

m month 1 - 12
mm month 01 - 12
mmm local abbreviation for month Jan - Dec
mmmm local name for month January - December
d day 1 - 31

-122-
DataFlex 3.2 Data Dictionary Guide

dd day 01 - 31
ddd local abbreviation for day of week Sun - Sat
dddd local name for day of week Sunday - Saturday
yy 00 - 99
yyyy 1700 - 2900
/ diagonal is replaced with the local date separator

field_mask_type integer iField — integer — mask_window | mask_numeric_window |


mask_date_window | mask_currency_window

This property controls the mask type of the field. This property may be set to any mask
type consistent with the data type of the field. Doing so will automatically use the default
mask (if any) for the mask type. Use of mask_currency_window will apply a mask
generated from the default_currency_mask ($,*;($,*)) for the field, where $ represents
the local setting for currency symbol in Windows. Use of mask_numeric_window will
apply a mask generated from the default_numeric_mask (*). The field_mask property
can be used to specify the mask for fields of any mask type, and will override the defaults
of those types that have defaults.

field_options integer iField — integer ... integer — property ... property

This property is used to set the field properties of a field. It can be passed any number of
property arguments, in any order, separated by spaces. In combination, these comprise
an (internal) Integer value that can be setted and getted as such (a single Integer).

Example:
Set Field_Options field ORDERHEA.TOTAL to DD_DISPLAYONLY
Set Field_Options field orderhea.Number to DD_AutoFind DD_NoPut

The options that can be set are:

DD_AutoBack
DD_AutoFind
DD_AutoFind_GE
DD_AutoReturn
DD_CapsLock
DD_DisplayOnly
DD_FindReq
DD_ForcePut
DD_NoEnter
DD_NoPut
-123-
DataFlex 3.2 Data Dictionary Guide

DD_Required
DD_Retain
DD_Retain_All
DD_SkipFound
DD_Zero_Suppress

Two additional parameters are supported to allow item options to be cleared. Those are:

DD_Clear_Field_Options

Clear all field properties passed after this parameter.

DD_Clear_All_Field_Options

Clear all field properties for this field.

field_prompt_object integer iField — integer — object_ID

Used to get/set the ID of the Prompt_Object for a field. This may often be an object to
display choices and/or validation values, such as ValidationList.

field_select_state integer iField — boolean — true | false

This procedure sets the field’s state in the local buffer. It notifies DEOs if the value of the
field has changed.

field_validate_msg integer iField — integer — msg_ID

The ID of the message to be sent on item validation and exit.

field_value_check integer iField — string — list

This defines the field to use check-type validation. Any entry will be validated against the
values defined in the check string. Each item in the check string is delimited by the “|”
character.

Example:
Set Field_Value_Check field customer.state to “CA|FL|NY|MA”

field_value_range integer iField — string string — lowValue HighValue


-124-
DataFlex 3.2 Data Dictionary Guide

This sets the field to use range-type validation and defines the minimum and maximum
range for this field. It is expected that the field and its range will be numeric or date. The
first string must be a lower value than the second string. If a spin form addresses iField,
its range will be set by the values of this property. In such a case, bear in mind that spin
forms have a range limit of 32K and a value limit of ±32K.

Example:
Set Field_Value_Range field customer.discount to 40 60

field_value_table integer iField — integer — object_ID

This identifies an object containing eligible values for iField. Usually, the items of an
object so used should be kept sorted, or in whatever custom order may be desired. The
classes designed for this use include ValidationTable, DescriptionValidationTable,
FileValidationTable, and CodeValidationTable.
Set Field_Value_Table field OrderHea.Via to (Ship_Table(Current_Object))
:
Object Ship_table is a CodeValidationTable
Set Validate_State to False
Set Type_Value to "SHIPPING"
Set Static_State to TRUE
Set No_Fill_State to TRUE
Set Allow_Blank_State to True
End_Object

field_zoom_object integer iField — integer — Object_ID

Used to Get/Set the ID of the zoom_object for a field

find_permissive_state — boolean — true | false

If the value of this property is true, find requests originating from DEOs attached to this
object (via request_find or item_find) may temporarily suspend this object’s constraints
to find a record outside of the current file subset. After a successful find and relate, the
constraints are reactivated to insure that the record found satisfies their encoded view,
and all connected DSOs are notified of the result of the find. For example, in an
application allowing usersto edit parts carried in stock grouped by vendor, we may have
the following DSOs:
object headerDD is a vendor_datadictionary
end_object

-125-
DataFlex 3.2 Data Dictionary Guide

object itemDD is an inventry_datadictionary


send attach_server (headerDD(current_object))
begin_constraints
constrain inventry relates to headerDD
constrain inventry.status eq in_stock
end_constraints
end_object

After finding a vendor, itemDD would find the first inventry record for the current vendor that
has status eq in_stock. Ordinarily, if a user tried to find an inventry record (perhaps by
part_number or description) which did not relate to the current vendor record, the find would fail.
If, however, find_permissive_state of itemDD had been set to true, i.e., set
find_permissive_state of (itemDD(current_object)) to true, the user would be permitted to find an
inventry record that did not relate to the current vendor record (or have status eq in_stock).
After itemDD had found (and related) such a record, it would reactivate its constraints. If
the new record did not satisfy the constraints (i.e. status ne in_stock), another find would
be attempted (unless this was an attempt to find eq). After a new record has been found
that satisfies itemDD's constraints, itemDD would inform headerDD of the result, causing
headerDD to "latch on" to the new vendor record (i.e., to whichever vendor record the new
inventry record relates).

Note that find_permissive_state does not affect finds requested as a result of scrolling
in a list or grid.

foreign_field_options integer iField — integer ... integer — property ... property

When an entry item refers to a file.field that is an ancestor of its DSO’s main file, that field
is considered to be a foreign field. Very often foreign fields require additional item-option
settings. For example, a foreign field may require an additional DD_NoPut or
DD_Displayonly. The foreign_field_option message allows you to assign additional
item options to a field when that field is used as a parent field. See the Field_options
property for a complete list of available field properties.

Example:
Set Foreign_Field_Options Field Customer.Address to DD_Displayonly

Often foreign fields will be assigned field properties based on whether the field is a key
field, an index field, or a non-indexed (default) field. It is common for a key field to be
DD_autofind and DD_noput, for an index field to be DD_noput, and for a non-indexed
field to be DD_displayonly. Three special iField values allow you to set properties for all
fields of these types. These integers are DD_KEYFIELD, DD_INDEXFIELD, and
DD_DEFAULT.

-126-
DataFlex 3.2 Data Dictionary Guide

Examples:
Set Foreign_Field_Options DD_KEYFIELD to DD_AUTOFIND DD_NOPUT
Set Foreign_Field_Options DD_INDEXFIELD to DD_NOPUT
Set Foreign_Field_Options DD_DEFAULT to DD_DISPLAYONLY

in_use_state — boolean — true | false

If the value of this property is true, this object has at least one active user-interface object
or one of this object’s containers is in use. Set by add_user_interface,
remove_user_interface, and activate. Setting the value of this property to true will
cause all ddo_servers of this object to set their in_use_state(s) to true. Setting the value
of this property to false may cause all ddo_servers of this object to set their
in_use_state(s) to false if this object was their only in-use client. Similarly, this object
may refuse to set its in_use_state to false if one (or more) of its clients is still in use.

key_field_state integer iField — boolean — true | false

DSOs allow you to define a single primary key for any file. Although there can be only one
key, the key can consist of multiple fields. Such a key is defined by setting all its fields’
key_field_states to true.

Example:
Set Key_Field_State field Customer.Number to True

main_file — integer — file_number

Identifies the file managed by this object. The file must be related to the main file of every
DSO updated (by attach_server) by this object. If the value of this property is changed,
this object sends main_file_changed, passing the number of the new main file, to notify
child-file DSOs of the change.

no_delete_state — boolean — true | false

If the value of this property is true, delete operations on the data managed by this object
are not permitted. Sending request_delete to this object when this property is true will
have no effect, nor will deletes of parent records (in updating DDOs) cause deletions in
the main_file of this object.

no_relate_state — boolean — true| false

-127-
DataFlex 3.2 Data Dictionary Guide

If the value of this property is true, the relate command will not be executed after any find
performed by this object. Note that certain constraints, i.e., child relates to parent, may
not be enforceable if relates do not occur. This property is intended to be get/set. Note
that the relate_main_file message will always be sent regardless of the value of
no_relate_state.

ordering — integer — -1 — index_number

The value of this property specifies the index which should be used for all find operations.
If the value is negative one (-1), no index restrictions are enforced. Note that if this
property is greater than or equal to zero, the corresponding index will be used for all find
operations. Set by by option of object-creation statement.

protect_key_state — boolean — true | false

When this property is true, it prevents users from changing the value of any key field. If
the DDO detects that a key value for an existing record has been changed, the
transaction will be aborted.

read_only_state — boolean — true | false

If this flag is true, no saving or deleting will occur to this object's main_file.
Request_save and request_delete messages are ignored if this flag is true, and delete
cascading is stopped (along this branch). (Updated) DSOs of parent files, however, may
still effect changes to this object’s main_file, and cause the record to be changed and
saved. In addition, entry_update messages are still sent to the DEOs of this object.

smart_filemode_state — boolean — true | false

This property governs whether this object can use file-locking optimization for its data
files. The default value of smart_filemode_state is defined in DFALLENT.PKG as the
constant DEFAULT$SMART$FILEMODE$STATE. As supplied, the constant sets default
smart filemode off with the line:
define DEFAULT$SMART$FILEMODE$STATE for FALSE

If you change this to true (and you are encouraged to do so) you should check all views in
your existing applications and make sure that there are no unknown files used in DDOs in
those views. If there are, you can set smart_filemode_state to false in the DDOs that
utilize unknown files (which makes all views that use those DDOs operate in non-smart
filemode).
-128-
DataFlex 3.2 Data Dictionary Guide

status_help integer iField — string — help_text

Gets/Sets status-line help text for the passed field.

suggested_ordering — integer — -1 — index_number

This property holds the number of an index to be used instead of recnum when finding by
best_index in this object. Set by data_lists on activation.

validate_delete_structure_mode — integer — DD_validate_structure_always |


DD_validate_structure_once |DD_validate_structure_never

This determines what type of DSO-structure validation will occur before a delete. Before a
delete, the actual DSO structure can be compared with the required DSO structure. If the
required structure is not complete, the delete will be disallowed. You can perform this
structure checking just once before the first delete (DD_validate_structure_once),
before every delete (DD_validate_structure_always) or never
(DD_validate_structure_never). Since DSO structures tend to be static, checking the
structure one time is usually sufficient.

validate_save_structure_mode — integer — DD_validate_structure_always |


DD_validate_structure_once | DD_validate_structure_never

This determines what type of DSO structure validation will occur before a save. Before a
save, the DSO structure can be compared with the required DSO structure. If the
structure is not complete, the save will be disallowed. You can perform this structure
checking just once before the first save (DD_validate_structure_once), before every
save (DD_validate_structure_aways) or never (DD_validate_structure_never). Since
DSO structures tend to be static, checking the structure one time is usually sufficient.

Advanced Interface

always_refresh_state — boolean — true | false

Setting this property true defeats optimizations of find operations in multi-file hierarchies
in views. It should not be changed except for debugging purposes.

cascade_delete_structure_validated_state — boolean — true | false

-129-
DataFlex 3.2 Data Dictionary Guide

When a DSO structure has been validated for a cascade delete, this property is set to
true. The value of this property is maintained by this object. It can be queried but should
not, under normal circumstances, be set. This property is used internally to allow a delete
structure to be validated only once in a session.

current_field_validation — boolean — error_num

This is set by the system when a field is validated. The DD sets this property in Function
Validate_field and sets it to zero when validate_field is exited.. The local error handler
will use this to determine if an error is a field error and what the field error is. This property
should not be set.

current_record — integer — record_number

The number of the record most recently retrieved from the database. This value becomes
zero after a buffer clear, and so is always zero at the time of saving a new record. Edited
records, however, retain the value of this property throughout editing. The value of this
property should not be set.

existing_key_value — string — value

This property holds the concatenated values of all the fields that have been flagged to be
key fields. It is used to check whether a user has changed the value of one of the fields
which make up a record’s key.

extended_error_message — string — File: File# LogicalFileName


Field: Field# FieldLabel

This is called by the standard Visual DataFlex error handler when a data-dictionary error
occurs. The argument beginning with Field is displayed on a separate line, and is
returned only if there is a field (current_validate_field is non-zero). You could augment
this to pass additional or changed lines of error information to the eror handler.

field_class_name integer iField — string — className

The suggested class of object for interfacing with iField, for such purposes as dynamic
objects in views. Accessed primarily by the Database Selector and set through the
Database Builder.

-130-
DataFlex 3.2 Data Dictionary Guide

field_label_long integer iField — string — description

A long description (or translation) of the name of iField for such purposes as form
captions. Accessed primarily via the DD_LABEL_LONG parameter of the field_label
property and set through Database Builder. Default value is that of field_label_short.

field_label_short integer iField — string — description

A short description (or translation) of the name of iField for such purposes as grid column
headings. Accessed primarily via the DD_LABEL_SHORT parameter of the field_label
property and set through Database Builder. Default value is that of field_tag_name.

field_tag_name integer iField — string — tag_name

The tag name of iField in the file definition proper. Accessed primarily via the
DD_LABEL_TAG parameter of the field_label property and set through Database
Builder only upon field creation.

no_cascade_delete_structure_validated_state — boolean— true | false

When a data-server structure has been validated for a no-cascade-delete, this property is
set to true. The value of this property can be queried but should not, under normal
circumstances, be set. This property is used internally to allow a delete structure to be
validated only once in a session. DDOs recognize that different data-server structures
may be required for cascade-delete and no-cascade-delete operations, and maintain
separate properties to indicate if cascade-delete and no-cascade-delete structures are
valid.

save_structure_validated_state — boolean — true | false

When a data-server structure has been validated for a save, this property is set to true.
The value of this property can be queried but should not, under normal circumstances, be
set. This property is used internally to allow a save structure to be validated only once in
a session.

smart_filemode_for_lock — integer — DF_FILEMODE_ORIGINAL |


DF_FILEMODE_READONLY | DF_FILEMODE_DEFAULT |
DF_FILEMODE_SINGLE_USER

-131-
DataFlex 3.2 Data Dictionary Guide

The value of this property is used by reset_filemodes_for_lock as the filemode of


database files involved in save or delete operations under lock optimization that are
evaluated as eligible to participate in the save. The default value of
DF_FILEMODE_ORIGINAL leaves unchanged whatever filemode each such file is open
as at the time of the save/delete (the property has no effect). If you should desire all such
files to be temporarily set to some other filemode for some DDO(s), you may set this
property to that filemode.

smart_filemode_for_no_lock — integer — DF_FILEMODE_READONLY |


DF_FILEMODE_DEFAULT | DF_FILEMODE_SINGLE_USER |
DF_FILEMODE_ORIGINAL

The value of this property is used by reset_filemodes_for_lock as the filemode of


database files involved in save or delete operations under lock optimization that are
evaluated as ineligible to participate in the save/delete. The default value of
DF_FILEMODE_READONLY leaves the files unlocked, improving both the speed of the
save/delete operation and user access to the ineligible files. If you should desire all such
files to be temporarily set to some other filemode for some DDO(s), you may set this
property to that filemode.

validate_deos_only_state — boolean — true | false

When set true, this property limits validation to fields that are represented in the current
view. In this state, it can allow data-integrity failures.

validate_foreign_file_state — boolean — true | false

When set false, this property prevents validation on save in this object when this object’s
file is an ancestor to the file whose record is being saved. It also prevents validation of
this object’s file’s ancestor files. This can be used to improve performance in data
dictionaries for files that cannot be changed from the program except as primary files. It
should never be used on a file in which data changes may be entered relationally.
Methods
Note that some procedures and functions are documented in the “Properties” section
above.
Normal Interface

add_system_file integer file_number [integer lock_type] — procedure

-132-
DataFlex 3.2 Data Dictionary Guide

This procedure adds file_number to the data-dictionary structure. It is used for system
files and other files that, although part of the locking structure, do not have their own
DDOs through which to connect to the data-dictionary structure. Lock_type specifies the
type of locking to be used with file_number:

DD_lock_on_all Lock on all saves and deletes


DD_lock_on_new_save_delete Lock on new saves and deletes
DD_lock_on_save Lock on all saves
DD_lock_on_new_save Lock only on new saves
DD_lock_on_delete Lock only on deletes

For system files supporting unique ID serial numbers, DD_lock_on_new_save should be


sufficient; for files supporting counters that increment and decrement, the other two
modes would be required, so DD_lock_on_all would be appropriate. Files can be
removed with remove_system_file.
Send Add_System_File OrdSys.File_Number DD_Lock_On_New_save

attach_main_file — procedure

Performs attach command on main file. Intended for augmentation or override. For
example, to manually enforce a relationship, we could augment this procedure to set the
value of the related-from field in the child file (see also: relate_mainfile):
class child_ds is a DataDictionary
:
procedure attach_main_file
forward send attach_main_file
move parent.relatedtofield to child.relatedfromfield
end_procedure
:
end_class

backout — procedure

Should reverse effects of update on database files which are related to by the main_file
of the data set. No action by default. Intended for augmentation or override. Note that this
operation is invoked while the database is locked.

can_delete returns boolean — function

This function is used by DEOs to determine if a delete of the current record is permitted.
The function respects the read_only_state and no_delete_state of this object.

-133-
DataFlex 3.2 Data Dictionary Guide

Can_delete returns true if all of the following conditions are true:

• main_file >0
• current_record >0
• this object is in-use
• this object is not read-only (saves/deletes are permitted)
• this object is not no-delete (deletes are permitted)

The conditions checked by can_delete are used to guard the request_delete message
(kdelete accelerator-key procedure) in the data-entry classes, so that if can_delete
returns false, request_delete takes no action. This is consistent with the behavior of
request_save.

clear — procedure

Clears all files owned by this object, including the main_file, sends refresh to the DEOs
attached to this object, sets the changed_state of this object to false and notifies
connected DSOs of the change. This may cause the connected DSO to clear and/or find,
etc. Sent by DEOs attached to this object.

clear_all — procedure

Clears all files owned by this object and all connected servers. Sends refresh
(mode_clear_all) to notify DEOs. Sent by DEOs attached to this object.

clear_main_file — procedure

This message performs the clear command on the main file of this object and is sent
whenever the buffer for the main file of a server must be cleared. It is intended to be
overridden or augmented. For example, to force a manually related file (see the
relate_main_file message) to be cleared when the main file is being cleared. Typically,
the request_clear_file message should be used for this purpose to insure the refresh of
DEOs occurs properly (see request_clear_file).
procedure clear_main_file
forward send clear_main_file
send request_clear_file manual1.file_number
send request_clear_file manual2.file_number
end_procedure

clear_ui — procedure

-134-
DataFlex 3.2 Data Dictionary Guide

Clears all DEOs attached to this object using the refresh (find_or_clear_set) message.
This message does not set changed_state of DEOs to false directly. DEOs may set their
own changed_state to false as a result of the refresh, however.

creating — procedure

The effects of creating a new record in the main file are implemented within the procedure
called creating. The creating procedure should only effect changes which are different
from update, since update will be invoked after creating automatically, and should only
contain commands that apply to the creation of a new record (i.e. assigning a unique ID
from a system_file field). Since creating is invoked while the database is locked, do not
use user-interface commands/messages within this procedure. This procedure is
intended for augmentation. For example, the DDO below assigns the vendor a unique ID
from a system file:
class vendor_dd is a DataDictionary
:
procedure creating
forward send creating
add 1 to sysfile.nextvendorid
move sysfile.nextvendorid to vendor.vendorid
saverecord sysfile
end_procedure
:
end_class

current_record returns integer — function

Returns the number of the record of the main file that is currently in the buffer. This
property may only be accessed (get); it may not be modified (set) directly.
Current_record is set indirectly by request_find, find_by_recnum, and
request_superfind.

delete_main_file — procedure

By default, this procedure performs a delete on the main_file. Intended for augmentation
or override. This procedure occurs to effect the actual removal of the main_file record.
For some objects, it may be appropriate to override this procedure, i.e., to set a field,
deleted_flag, to Y:

class afile_dd is a DataDictionary


:
procedure delete_main_file
-135-
DataFlex 3.2 Data Dictionary Guide

move "Y" to afile.deleted_flag


saverecord afile
end_procedure
:
end_class

Note that a DDO such as the one above would likely have the following constraint:
constrain afile.deleted_flag ne "Y"

to prevent the inclusion of "deleted" records in its defined set.

data_set_error integer iField integer error_number string text — procedure

This message declares DSO errors. Normally three parameters are passed to this
procedure: Field number, and the error number and error text defined for iField in the
field_error property. The field number is passed but not used. It is available so that this
information will be available to the procedure for use in any augmentation of it. When
iField is passed as -1, the originating field is unknown.
If error_number is 0, the DSO will use a default error number.

default_currency_string returns string — function

This function returns the value of the default currency string, default_currency_mask.
The currency character in this string returns the local currency symbol from the local
Windows environment.

define_fields — procedure

This procedure is called by construct_object and is designed to be augmented to set up


all data-dictionary rules. The main_file property must be set before any other property;
property settings that precede the setting of this property will not take effect.

Example: (see ordrds.ds example file for more detail):


Class Customer_Data_Dictionary is a DataDictionary
:
Procedure Define_Fields
Forward Send Define_Fields
Set Main_File to Customer.File_Number //this property must be set
//before all others
Set Cascade_delete_State to FALSE // don't delete if children exist
Send Add_Client_file Orderhea.File_Number//List client (child) file
//set foreign defaults
Set Foreign_Field_Options DD_DEFAULT to DD_DISPLAYONLY
// Define Individual Fields
-136-
DataFlex 3.2 Data Dictionary Guide

// Number
Set Key_Field_State field CUSTOMER.NUMBER to TRUE
Set Field_Options field CUSTOMER.NUMBER to ;
DD_AUTOFIND DD_NOPUT
Set Field_Prompt_Object field CUSTOMER.NUMBER to ;
(Cust_List_Prompt_List(Current_Object))

// Name
Set Field_Prompt_Object field CUSTOMER.CUSTOMER to ;
(Cust_List_Prompt_List(Current_Object))

// State
Set Field_Options field CUSTOMER.STATE to DD_CAPSLOCK
Set Field_Value_Check field CUSTOMER.STATE to "CA|WA|FL|NV|OR"

// Discount can not go below 0 or above 100%


Set Field_Value_Range field CUSTOMER.DISCOUNT to 0 100

Set Field_Options field CUSTOMER.ZIP to DD_Retain


Set Field_Options field CUSTOMER.PROFIT to DD_DISPLAYONLY

// Define Status Help for some fields


Set Status_Help field Customer.Number to ;
"System-assigned customer number."
Set Status_Help field Customer.Comments to ;
"Additional comments and notes."
End_Procedure // Define_Fields
:
End_Class

deleting — procedure

By default, this procedure does nothing except lock the database. It is intended for
augmentation or override by instances or subclasses. Its purpose is to perform any
database actions which are only required when a record (in the main_file) is deleted. This
operation occurs prior to backout and the actual removal of the main_file record.

display — procedure

No action (cancels inherited operation).

display_ui — procedure

Sends refresh (mode_find_or_clear_set) to all DEOs attached to this object.

field_current_description integer iField returns string — function


-137-
DataFlex 3.2 Data Dictionary Guide

This function returns the description for the current value of iField as listed in iField’s
validation table. This can be used to get at these descriptions within reports and batch
processes. If there is no description value, or no validation table, the value of iField itself
is returned.

field_defaults — procedure

This procedure is designed to be augmented to establish the default values that will
appear after a clear. You may set any field values, which will be reflected in the DEO
items and will get saved with the new records. Because the setting of the defaults is
coded in a procedure, complex rules may be set.

Example:
Procedure Field_Defaults
Set Field_Changed_Value field customer.state to "FL"
Set Field_Changed_Value field customer.discount to 10
Set Field_Changed_Value field customer.City to "Miami"
End_Procedure

field_label integer iField DD_LABEL_LONG| DD_LABEL_SHORT| DD_LABEL_TAG


returns string — function

This function returns the value of the field_label_long, field_label_short, or


field_tag_name property of iField.

field_main_index integer file_number integer field_number returns integer — function

This function returns the number of the index to use for finding on the specified
file_number and field_number. If this object has an ordering and the specified file_number
is the main_file, the ordering will be returned, regardless of whether the specified
field_number has a main index. If this object has no ordering, the main index of the field
will be returned. If the field has no main index and this object has no ordering, -1 is
returned.

find_by_recnum integer file_number integer rec_number — procedure

Finds record in specified file with record number equal to rec_number. If found, relates.
Sets found indicator. Affects the current_record of this object, and notifies any
connected DDOs of the change. Sent by lists and grids to find a record for a particular
row. May be used to find a specific record, i.e.:
-138-
DataFlex 3.2 Data Dictionary Guide

send find_by_recnum to (someDSO(current_object)) somefile.file_number 3

would find Record Number 3 for somefile. Note the use of .file_number; the first argument
to this procedure is a file number, not a file name. The filename.file_number symbol is
evaluated by the open command, and is the file number of the named file.

key_value returns string— function

This function returns the complete (all fields) key value for the current record.

new_current_record integer old_rec integer new_rec — procedure

By default, this procedure does nothing. It is received during the save, delete, and clear
operations. During a find/relate operation, the "origin" of the find receives this message
unconditionally, while the updated (parent) DDOs only receive it if the Current_Record is
changing. It is available as a hook by means of which you can do such things as keep
track of a key value:
procedure construct_object integer
forward send construct_object
set main_file to .....

property integer oldId public 0

end_procedure // construct_object

procedure new_current_record integer oldrec# integer newrec#


forward send new_current_record oldrec# newrec#
set oldId to myfile.key_field
end_procedure

function validate_save returns integer


local integer rec# newid# oldid# rval
forward get validate_save to rval
if rval function_return rval

get current_record to rec#


get oldid to oldid#
if (rec# <>0 and myfile.key_field <>oldid# ) ;
send operation_not_allowed 301 // custom error message
end_function // validate_save

operation_not_allowed integer error_num — procedure

-139-
DataFlex 3.2 Data Dictionary Guide

By default, this procedure simply executes the error command with the argument of
error_num. You may, however, augment it to substitute other messages for error_nums
defined in DataFlex, or undefined:
procedure operation_not_allowed integer err#
if err# eq 4140 error err# ". Customer has activity."
else forward send operation_not_allowed err#
end_procedure

rebuild_constraints — procedure

Reconstructs constraints for this object by sending constrain to it and to the servers,
recursively, of this object (thus ensuring that clients respect the constraints of their
servers).

relate_main_file — procedure

Performs relate command on main_file. Intended for augmentation or override. May be


overridden to inhibit finding using relationships, or may be augmented to manually enforce
relationship, i. e.:
class child_dd is a DataDictionary
:
procedure relate_main_file
forward send relate_main_file
clear parent
move child.relatedfromfield to parent.relatedtofield
find eq parent.relatedtofield
if [found] send request_relate parent.file_number
else send request_clear_file parent.file_number
end_procedure
:
end_class

This ensures that the appropriate parent record is found whenever a new child record is
found. While relate_main_file may be augmented or overridden, canceling the behavior
of this procedure will not prevent a relate from being executed on the main_file. To
prevent relates on the main_file completely, set no_relate_state to true. Note that the
relate_main_file message will always be sent regardless of the value of
no_relate_state. (See also: attach_main_file.)

remove_system_file file_number — procedure

A system or other file added to the DSO structure with the add_system_file message
may be removed from the DSO structure with this message.
-140-
DataFlex 3.2 Data Dictionary Guide

request_assign integer file_number — procedure

Causes the refresh message to be sent to all DEOs for this object and its client and
server DDOs as appropriate. This is to ensure that all DEOs properly display the record
for the current record buffer. If the currently active record (in the record buffer) for the
specified file_number satisfies this object’s constraints, this object "latches on" to the
currently active record, and notifies its clients and servers of the change, if necessary. If
the current record does not satisfy the constraints, no action occurs (except setting
found). This procedure sets the found indicator to true if the record satisfies the
constraints; false otherwise.

request_clear — procedure

See (and use) clear message.

request_clear_all — procedure

See (and use) clear_all message.

request_clear_file integer file — procedure

This message performs the clear command on the specified file of the data-server
structure. It is intended to be used to clear a file and notify this object that the file is
actually cleared. This ensures that the refresh of data-entry objects that may occur
afterwards will properly clear entry_items for the specified file. (If the clear command
alone is used, the refresh will not clear the entry_items for the specified file). It is
intended to be used in an augmentation of the clear_main_file procedure to force a
manually related file (see the relate_main_file message) to be cleared when the main file
is being cleared.
procedure clear_main_file
// clear_main_file normally
forward send clear_main_file
// also clear "manually" related files
send request_clear_file manual1.file_number
send request_clear_file manual2.file_number
end_procedure

request_delete — procedure

-141-
DataFlex 3.2 Data Dictionary Guide

Deletes current record, if any, in the main_file of this object, else issues an error. Sent by
DEOs attached to this object. Note that deletion of the current main_file record may
cause sets of records in parent-file DDOs to be deleted, i.e., those records which relate to
this object's current record. Sends can_delete and acts only if that returns true.
If you send this message to a DDO from the program (rather than from a DEO), precede
this with entry_update 0 1 to make sure the file buffer contains the record you intend to
act on.

request_find integer find_mode integer file integer index — procedure

Finds on specified file using given find_mode and index. If find is successful, performs a
relate on file. If file is the same as this object's main_file, sends relate_main_file.
Notifies other connected DSOs of the result of the find. Find_mode may be any of the
standard find modes, i.e. lt, le, eq, ge, or gt, or it may be either next_record,
first_record, or last_record. Sets the found indicator to reflect the success or failure of
the find operation. Sent by DEOs and item_find.

If you send this message to a DDO from the program (rather than from a DEO), precede
this with entry_update 0 1 to make sure the file buffer contains the record you intend to
act on.

request_read integer find_mode integer file integer index — procedure

Finds on specified file using given find_mode and index. If find is successful, performs a
relate on file. If file is the same as this object's main_file, sends relate_main_file.
Find_mode may be any of the standard find modes, i.e. lt, le, eq, ge, or gt, or it may be
either next_record, first_record, or last_record. Sets the found indicator to reflect the
success or failure of the find operation. Sent by deferred DEOs and by lists and grids.
If you send this message to a DDO from the program (rather than from a DEO), precede
this with entry_update 0 1 to make sure the file buffer contains the record you intend to
act on.

request_relate integer file_number — procedure

Performs a relate on the specified file_number without initializing the done-array.


Intended to be sent within the relate_main_file procedure to inform this object that a
successful manual relationship has been performed. Sending this message is required so
that fields from the target file and its parents will be properly displayed on the DEOs of this
object. For example:
class lineitem_dd is a DataDictionary
-142-
DataFlex 3.2 Data Dictionary Guide

:
procedure relate_main_file //perform a manual relate to INVT
forward send relate_main_file
clear invt
move lineitem.part_id to invt.part_id
find eq invt.part_id
if [found] send request_relate invt_DD
else send request_clear_file invt_DD
end_procedure
:
end_class

Note that request_relate is only sent if the find was successful, and that the target of the
manual relationship (a DDO for invt) must be attached by ddo_server to the child DSO.
If you send this message to a DDO from the program (rather than from a DEO), precede
this with entry_update 0 1 to make sure the file buffer contains the record you intend to
act on.

request_save — procedure

Saves all changes in DEOs attached to this object or to any DDO that is a server of this
object directly or indirectly. Sent by DEOs attached to this object.
If you send this message to a DDO from the program (rather than from a DEO), precede
this with entry_update 0 1 to make sure the file buffer contains the record you intend to
act on.

save_main_file — procedure

Performs a saverecord on the main_file of this object. Intended to be augmented, i.e., to


save an unrelated file such as a system file. Sent as part of save operation.

transaction_aborted integer errcode — procedure

No action by default. Sent after rollback completed as a result of validate_save failure.


Intended for augmentation. The value of errcode is the value returned by the
validate_save that failed.

update — procedure

Should effect changes to main file in related files. No action by default. Intended for
augmentation or override. Note that this operation is invoked while the database is locked.
Note also that the backout procedure should undo the effects of this procedure.

-143-
DataFlex 3.2 Data Dictionary Guide

validate_constraints returns integer — function

This function validates this object's constraints against the record buffer's current content,
returning true if the constraints are satisfied, or false if they are not satisfied. This
function is intended to be used within validate_save procedures to verify that records
satisfy this object's constraints. Note that most constraints are merely selection criteria
and not integrity rules, so use of this function would probably be rare.

validate_delete returns integer — function

No action by default. Intended for augmentation. Used to guard execution of delete


operation. Should return zero if deletion is allowed, else should return non-zero or
generate an error to prevent deletion. By default, returns zero to allow deletion. This
function is intended to check for possible data-integrity violations, not prompt the user. For
example, to prevent the deletion of unposted related invoices:
class invoice_dd is a DataDictionary
:
function validate_delete returns integer
local integer retval
// always forward the message
forward get validate_delete to retval
if retval function_return retval
// generating an error will stop the delete.
if invoice.status ne posted_status ;
error 300 "Can't delete this status"
end_function
:
end_class

validate_field integer iField returns boolean — function

This function is called to validate a field.

validate_save returns integer — function

No action by default. Intended for augmentation. Used to guard commit of save operation.
Should return 0 if saving is permissible, else non-zero, which prevents saving. You may
also prevent the save by generating an error in the function. By default, returns 0 to allow
saving. Note that this operation is intended to prevent invalid data from being written to
the database, and should not be used to ask users if they really want to save changes,
nor should it perform any other user-interface-related tasks. If this function returns a non-
zero value, the current save operation will be aborted, and the records involved "rolled
-144-
DataFlex 3.2 Data Dictionary Guide

back" to their original values; then the transaction_aborted message is sent. This
function should be used to enforce business rules and integrity rules, for example:
class customer_dd is a DataDictionary
:
function validate_save returns integer
local integer retval
// always forward the message
forward get validate_save to retval
if retval function_return retval
// generating an error will stop the save
if customer.credit_limit lt customer.balance ;
error 303 "Customer exceeds credit limit."
end_function
:
end_object

Note that enforcement of this rule is done in the DDO for the customer file, and not in the
DDO(s) for invoice and lineitem. If cust_dd is used in conjunction with invoice_dd, invoice_dd will
respect cust_dd's rules as long as cust_dd is updated by invoice_dd.

which_data_set integer file_number returns integer — function

Returns ID of object owning specified file_number, or 0 if neither this object nor any of its
servers owns the specified file_number.

Advanced Interface

add_client_file integer file_number — procedure

This procedure adds File file_number to this object's container-file list.

add_focus integer base_object returns integer — procedure

Adds this object into the focus tree as a child of the specified base_object, and sets
in_use_state to true.

add_parent_file integer file_number — procedure

Adds File file_number to this object's parent-file list if it is not already a member, i.e.:
object a_ds is an a_data_set
send add_parent_file anotherfile.filenumber
end_object
-145-
DataFlex 3.2 Data Dictionary Guide

You are encouraged to do updating on DSOs, and not on files.

add_server_file integer file_number — procedure

This procedure adds File file_number to this object's server-file list.

add_user_interface integer object_id — procedure

Adds specified object_id to the set of DEOs attached to this object. Sent by DEOs upon
activation, to attach to their server. If the auto_fill_state of the specified object_id is true,
and it is the first auto-fill DEO to be attached to this object, this object changes its
auto_fill_state to true after storing the original value of the state, so that if the DEO is
later detached by use of remove_user_interface, the auto_fill_state of this object can
be restored.

attach_client integer DDOname— procedure

Establishes connection between this object and the specified object_id, with this object as
the server of DDOname, and DDOname as a client of this object. Note that the
connection is two-way. Intended to be sent to attach new DDOs as clients of an existing
DDO, i.e.:
object dd1 is a parent_dataDictionary
end_object
object dd2 is a child_dataDictionary
end_object
send attach_client to (dd1(current_object)) (dd2(current_object))

Since the connection is two-way, attach_client and ddo_server accomplish the same
goal, but from different perspectives, i.e., client and server, respectively.

attach_deo_to_server integer — procedure

No action (cancels inherited operation).

attach_server integer DDOname — procedure

Establishes connection between this object and the specified DDOname, with this object
as the client of DDOname, and DDOname as a server of this object. Note that the

-146-
DataFlex 3.2 Data Dictionary Guide

connection is two-way. Intended to be sent to attach new DDOs as server of an existing


DDO
object dd1 is a parent_dataDictionary
end_object
object dd2 is a chld_dataDictionary
end_object
send attach_server to (dd2(current_object)) (dd1(current_object))

Since the connection is two-way, attach_client and attach_server accomplish the same
goal, but from different perspectives, i.e., client and server, respectively.

client_file integer list_pos returns integer — function

This function returns the number of the file at Position list_pos in this object's container-
file list.

client_file_count returns integer — function

This function returns the number of files in this object's container-file list.

constrain — procedure

Defines constraint set for this object, using constrain_file. Augmented by


begin_constraints ... end_constraints block, if any.

data_set integer iFile returns integer— function

This function returns the ID of the DDO whose main file is iFile.

data_set_client integer list_pos returns integer — function

This function returns the object ID of the DDO at Position list_pos in this object's
container-DDO list.

data_set_client_count returns integer — function

This function returns the number of DDOs in this object's container-DDO list.

data_set_server integer list_pos returns integer — function


-147-
DataFlex 3.2 Data Dictionary Guide

This function returns the object ID of the DDO at Position list_pos in this object's server-
DDO list.

data_set_server_count returns integer — function

This function returns the number of DDOs in this object's server-DDO list.

data_set_user_interface integer list_pos returns integer — function

This function returns the object ID of the DEO at Position list_pos in this object's user-
interface-DEO list.

data_set_user_interface_count returns integer — function

This function returns the number of DEOs in this object's user-interface-DEO list.

destroy_object — procedure

This procedure destroys this object if it is not in use.

detach_client integer DDOname — procedure

Disconnects this object from the specified DDOname if DDOname is a client of this
object; otherwise, no action. Intended to break the connection between two connected
DSOs, i.e.:
send detach_client to (dd1(current_object)) (dd2(current_object))

detach_server integer DDOname — procedure


Disconnects this object from the specified DDOname if DDOname is a server of this
object; otherwise, no action. Intended to break the connection between two connected
DDOs, i.e.:
send detach_server to (dd2(current_object)) (dd1(current_object))

end_construct_object — procedure

-148-
DataFlex 3.2 Data Dictionary Guide

This message is augmented to set the focus_mode of the object to nonfocusable if the
object contains no children. This prevents a DDO with no children from automatically
receiving the focus.

entry_clear boolean cleared_files_only — procedure

No action (cancels inherited operation). If cleared_files_only is true, only items for files
which have been cleared in the current data-server operation will be affected.

entry_clear_all boolean cleared_files_only — procedure

No action (cancels inherited operation). If cleared_files_only is true, only items for files
which have been cleared in the current data-server operation will be affected.

entry_display integer file_number boolean display — procedure

No action (cancels inherited operation).

entry_update integer file_number boolean do_all — procedure

No action (cancels inherited operation).

establish_find_direction integer find_mode integer file integer index — procedure

Initializes the constrained find commands to perform searches using the given
find_mode, file, and index. Find_mode may be any of the standard find modes, i.e. lt, le,
eq, ge, or gt, or it may be either next_record, first_record, or last_record. Sent by lists
and grids as part of their fill_page procedure. For example:
send establish_find_direction ge teile.file_number 1

exit_application_check returns boolean — function

This message is broadcast to child objects (of which there would normally be none) on
deactivation of this object to check their should_save state. If any is true, the
deactivation is aborted. The should_save state of this object is not checked.

field_count returns integer — function

This function returns the number of fields in the object.


-149-
DataFlex 3.2 Data Dictionary Guide

field_error_message integer iField— function

Used to retreive the error message for a particular field.

field_error_number integer iField — function

Used to retreive the error number for a particular field.

field_option integer iField integer iOption returns boolean — function

This function returns the state of the passed field property for iField—that is, whether the
property is (true) or is not (false) in force for the field..

find_server returns integer — function

Used by child sets to locate parent server. Returns ID of this object if its main_file is non-
zero.

init_instance — procedure

This procedure initializes the instance. It is sent internally and should not be augmented
or overridden.

is_superfind_required integer file returns boolean — function

Returns true if a find on the specified file must be converted into a superfind (to satisfy
entry_permissive_state). Sent by item_find.

item_find integer find_mode integer file integer field boolean entry_update boolean
report_errors boolean deferred_state — procedure

Performs a find based on the specified find_mode, file, and the main index of field.
Entry_update specifies whether an entry_update is required, report_errors specifies
whether find statuses past/prior end/beginning of file should be reported, and
deferred_state specifies whether to notify connected data sets. Find_mode may be any of
the standard find modes, i.e., lt, le, eq, ge, or gt, or it may be either next_record,
first_record, or last_record. Sets found indicator to true if successful, false otherwise.
Sent by DEOs. For example:
-150-
DataFlex 3.2 Data Dictionary Guide

send item_find to (hommes_ds (current_object)) ge hommes.file_number 1 ;


false true false

The above would find ge hommes using the main index of the first field or the ordering of
hommes_ds, if any. No entry_update would be sent to the DEOs of hommes_ds, a find past
the end of hommes_ds's defined set will report an error, and if the find is successful, other
connected DSOs will be notified.

locate_next — procedure

Finds the next logical record using the find_mode, file, and index specified in a prior
establish_find_direction invocation. Sent by lists and grids as part of their fill_page
procedure. Sends relate_main_file if successful. Does not affect current_record of the
data set, nor does it notify other (connected) data sets of the result.

locate_server returns integer — function

Used by connected DEOs to locate server. Returns ID of this object if its main_file is
non-zero.

main_file_changed integer file — procedure

Used as notification to child-file DSOs that a parent-file DSO has changed its main_file. If
this object has a parent-file DSO, it will reset the parent file to which the main_file of this
object must be related. Sent by parent-file DSO when its main_file is changed.

mark_as_component — procedure

Sets component_state of this object and has_components_state of parent object to


true, determines if this object should attach to its parent object as a client. Rebuilds the
constraint set for this object by sending rebuild_constraints.

parent_file integer list_pos returns integer — function

This function returns the number of the file at Position list_pos in this object's parent-file
list.

parent_file_count returns integer — function

-151-
DataFlex 3.2 Data Dictionary Guide

This function returns the number of files in this object's parent-file list.

read_by_recnum integer file integer rec_number — procedure

Finds record in specified file with record number equal to rec_number. If found, relates.
Sets found indicator. Does not affect the current_record of this object, nor does it notify
any connected DSOs of the change. Sent by lists and grids to re-find a record for a
particular row. Also sent by DEOs with deferred_state set to true.

refind_records — procedure

Used by connected DEOs to make certain that the record in the file buffer matches the
record the DEO "thinks" is there. Because a single data-file buffer can be used by multiple
DSOs in different views, you cannot always be sure that the buffer contains the correct
data for the view that the user is in. This is really only an issue when you create custom
procedures and functions in a DEO (the refresh message is the exception to this).
Anytime you need to access file-buffer information in a DEO (e.g., an iEntry, iValidate,
iExit message) you should first send refind_records to the DEO's server.
The following example shows a complex validate function. There is an entry item for
transact.type which can accept four values (1, 2, 3, and 4). 1 and 2 are valid if vndr.stat is A. 3
and 4 are valid if vndr.stat is I. Below is the entry-item and iValidate code.
entry_item Transact.Type {iValidate =GET_Check_Tr_Type}
:
Function Check_tr_Type Integer Item# Returns integer
Local Integer Typ
Send refind_records to (server(current_object))
Get Value Item Itm# to Typ // current value of type
// check if we have a valid stat
if not ((Vndr.Stat ='A' and (Typ =1 or Typ =2)) or ;
(Vndr.stat ='B' and (Typ =3 or Typ =4))) ;
function_return 1 // error condition
end_function

refresh integer mode — procedure

Displays items from some files at the same time as clearing items from other files. In all
cases, refresh will be sent instead of the clear, clear_set, clear_all, display, and
entry_display messages in response to a find, clear, clear_all, save, or delete. In some
cases, the actions of refresh depend on the (old) messages clear, clear_all, save, and
display.

-152-
DataFlex 3.2 Data Dictionary Guide

The mode, which signifies the event or operation which generated this refresh message,
may be one of the following five:

mode_clear - used only for DEOs attached to the DDO which was the "origin" of a clear
operation, i.e., the DDO which received the original clear request or message as a result
of the user pressing kclear. All other DDOs send their DEOs the refresh message
passing mode_find_or_clear_set.

mode_find_or_clear_set - used for DEOs attached to DDOs which have found and/or
cleared records in response to a user's find-request (kfind, kfind_next, ksuperfind, et
al.) or in response to another DDO's find or clear.

mode_clear_all - used for DEOs attached to any DDO which participated in a clear_all
operation.

mode_delete - used for DEOs attached to any DDO which performed a successful
deletion. DDOs that were merely updated as the result of a deletion use
mode_find_or_clear_set.

mode_save - used for DEOs attached to any DDO involved in a successful save
operation.

remove_object — procedure

Removes this object from the focus tree, and attempts to set in_use_state of this object
to false.

remove_client_file integer file_number — procedure

This procedure removes File file_number from this object's container-file list.

remove_parent_file integer file_number — procedure

Removes file_number from parent files of this object if file_number is actually a parent file
of this object. Otherwise, no action. Intended to be sended to make this object stop
updating one of its parent files. For example:
object ds3 is a file1_data_dictionary updating file2 file3
:
end_object

send remove_parent_file to (ds3(current_object)) file3.file_number


-153-
DataFlex 3.2 Data Dictionary Guide

remove_server_file integer file_number — procedure

This procedure removes File file_number from this object's server-file list.

remove_user_interface integer object_id — procedure

Removes specified object_id from the set of DEOs attached to this object. If object_id is
not attached to this object, no action occurs. If the removal of object_id from the set of
attached DEOs makes the set empty, this object attempts to set its in_use_state to
false. If the specified object_id's auto_fill_state is true and this object has no other auto-
fill DEOs, will cause auto_fill_state of this object to revert to original value. Sent by
deactivate procedure of DEOs to disconnect themselves from their server. Opposite of
add_user_interface.

request_entry_update integer file boolean do_all — procedure

Sends entry_update to all DEOs of the data set and DEOs of servers of the data set as
required to store changes to record buffers. Sent by request_save and item_find.

request_superfind integer find_mode integer file integer field — procedure

Performs superfind on the designated file by the main index of field and notifies all
connected DSOs of the result. Find_mode may be any of the standard find modes, i.e. lt,
le, eq, ge, or gt, or it may be either next_record, first_record, or last_record. Sets the
found indicator to reflect the success or failure of the find operation. Sends of
request_superfind to a DataSet require Predefined Indicator err to be set to false
beforehand, in case an error other than Find past end of file or Find prior to beginning
of file is generated by the superfind. Sent by DEOs.

request_validate returns integer — function

Performs validate_items on all DEOs attached to this object, and to all DEOs which
would be affected by a save of this object. Returns zero if all items are valid, else returns
a non-zero value. Sent by DEOs as part of request_save.

reset_filemodes_for_lock — procedure

-154-
DataFlex 3.2 Data Dictionary Guide

When smart_filemode_state is true, this procedure resets the filemodes of the


main_file of this object and of any updated DSO(s) for a save/delete operation and
restores them to their previous state after the operation is complete. Files determined
eligible for the save/delete (those relating to the record for which deletion was requested)
will have their filemodes changed (or not changed) according to the value of the
smart_filemode_for_lock property, while those determined ineligible will have theirs
changed to the value of smart_filemode_for_no_lock.

server_file integer list_pos returns integer — function

This function returns the number of the file at Position list_pos in this object's server-file
list.

server_file_count returns integer — function

This function returns the number of files in this object's server-file list.

should_save returns integer — function

Returns true if this object's changed_state or any of its server DSOs' changed_state(s)
is (are) true, or if they have found any new parent-file records. Sent by DEOs to guard
request_save.

validate_delete_no_cascade returns integer — function

When cascade_delete_state is false, validate_delete calls this function to check


whether any record related to the record for which deletion was requested exists in any
file named in an add_client_file message for this object. If any does, or if any named file
is not open, this function returns true, and calls operation_not_allowed. If all related
files are open and none contains a record related to the record for which deletion was
requested, this function returns false, allowing the deletion to proceed.

Please note: If you wish to employ cascade-delete checking and you have defined your
own validate_delete function, you must forward validate_delete; otherwise cascade-
delete checking will not occur.
function validate_delete returns integer
local integer rval
forward get validate_delete to rval // check cascade delete
if rval eq 0 begin // if ok so far,
: //custom checking

-155-
DataFlex 3.2 Data Dictionary Guide

end
function_return rval
end_function

validation_table_description integer validationObject string fieldValue returns string —


function

This message is used to get a description from the passed validation-table object for a
passed fieldValue. This could be used to check if a record with fieldValue exists and what
its description value is. If none exists, a blank is returned (which could be used to trigger a
value).
Function ValidateThis integer iField String sTestVal returns integer
local integer iValId
Local string sDesc
Get Field_Table_Object of iField to iValId
If iValId ;
get Validation_table_description iValId sTestVl to sDesc
function_Return (sDesc =””)
end_Function

File_field Messages
File_field_ messages perform the same function as their field_ message counterparts.
The difference between the two is that the file_field messages require that both a
filenumber and a fieldnumber be passed. When a DSO receives a file_field message, it
attempts to find the DSO within the current DSO structure whose main file has the passed
filenumber. It then sends this object the field_ version of the message. The file_field
messages can be thought of as “directors”. They find the appropriate DDO for the passed
filenumber and send a field_ message to that DDO.
Data-entry objects use this mechanism extensively to communicate with DSOs. You will
rarely need to use these messages yourself. The most-likely file_field message to be
used will be the file_field_current_value message. That can be used by a child data
file’s DSO to get the current value of a parent field.
See the field_ versions of these messages for a description of their purposes.

file_field_changed_state integer iFile integer iField — boolean

file_field_changed_value integer iFile integer iField — string

file_field_checkbox_value integer iFile integer iField boolean bTrue — string

file_field_class_name integer iFile integer iField — string — className

-156-
DataFlex 3.2 Data Dictionary Guide

file_field_tag_name integer iFile integer iField — string — tag_name

file_field_current_value integer iFile integer iField — string

file_field_default_value integer iFile integer iField — string

file_field_label_long integer iFile integer iField — string — description

file_field_label_short integer iFile integer iField — string — description

file_field_options integer iFile integer iField — integer

file_ field_prompt_object integer iFile integer iField — integer

file_field_select_state integer iFile integer iField — boolean

file_field_status_help integer iFile integer iField — string

file_field_validate_msg integer iFile integer iField — integer

file_field_zoom_object integer iFile integer iField — integer

Commands
begin_constraints

This macro begins a constraint block. Internally, it begins a procedure named constrain,
and forwards the constrain message.

define_auto_increment systemFileField to mainFileField

This command, placed in the define_fields procedure, enables you to designate one field
that will automatically increment the designated systemFileField and attach its value to the
designated mainFileField whenever a new record is saved.
define_auto_increment ordsys.cust# to customer.number

In this example, Field cust# in System File ordsys is designated to increment and provide a
value to Field number in Main File customer whenever a new record is saved in customer.
-157-
DataFlex 3.2 Data Dictionary Guide

end_constraints

This macro ends a constraint block. Internally, it executes an end_procedure command,


to end the constrain procedure created by the begin_constraints command.

ValidationTable

Purpose
To provide a one-column table of validation data statically defined within the object itself
for validation lists used through the field_value_table field property in DataDictionary
objects.
Hierarchy
Array
└─ValidationTable
└─DescriptionValidationTable

Source
DDVALTBL.PKG
Usage
use ddvaltbl

Object object_name is a ValidationTable


set table_title to title
Procedure Fill_list
Send Add_table_value value
:
end_Procedure
End_Object

Argument Explanation
object_name The name of the ValidationTable object
value A value to use for validation or prompting
title An optional text to describe or explain the list as a whole

-158-
DataFlex 3.2 Data Dictionary Guide

Of Special Note
This is a minimal validation object for assignment in DataDictionarys to database fields
with the field_value_table property. It provides only values for insertion into the
database. It is the superclass of a hierarchy of more-capable and -complex validation
classes, but is usable in its own right in simple, static situations.
If the validate_state property is set false, entries are permitted that are not in the list; in
its default true state, it requires an entry that matches one of the existing table items. If
the static_state property is set false, the fill_list procedure will be sent every time the
table is activated; in its default true state, the object is loaded with its list only once in
each session.
Properties

Normal Interface

allow_blank_state — boolean — true | false

This property controls whether blank entries are accepted in this object.

static_state — boolean — true| false

If this property is false, this object loads its list (with fill_list) every time it is requested to
validate or fill a foreign list. In its default state, it loads its list only once in each session. In
applications that allow editing of the list (“Code Maintenance” functions and the like) it is
important that this property be set false in order to give effect to such changes during the
sessions in which they are made.

table_title — string — title

This property may be used to present text at the top of the list to describe or explain the
list as a whole.

validate_state — boolean — true| false

If this property is false, entries to the field to which this object is assigned need not match
any of the values in this object’s list, which would in such case be used only to provide
suggested values and facilitate selecting among these. In its default state, it requires that
all entries exactly match one of the values in the list. Governs the sending of
validate_value.

-159-
DataFlex 3.2 Data Dictionary Guide

Advanced Interface

number_elements — integer — 1 — elements

This property specifies how many data elements (code only, 1; or code and description, 2)
are supported by the items of this object.
Methods

Normal Interface

add_table_value string value — procedure

This message should be sent for each value you desire to have in your validation table.
The messages should be sent in the order in which you wish to have values be presented
in the list.

fill_list string value — procedure

This procedure should be defined (with add_table_value messages) so as to contain all


the values required for validation.

validate_value string value returns boolean — function

This function, received from DEOs, returns zero when value is found to be valid, and non-
zero otherwise. You may augment it in this object. It is not sent when validate_state is
false.

Advanced Interface

request_fill_from_list integer object_id integer message_id — procedure

When this message is received, this object passes its data (code, description, etc.) for
each item of the list in turn to the display object_id as arguments to message_id, which
should be the ID of the message by which the display object fills its list.

-160-
DataFlex 3.2 Data Dictionary Guide

DescriptionValidationTable

Purpose
To provide a three-column table of validation data statiscally defined within the object
itself for validation lists used through the field_value_table field property in
DataDictionary objects.
Hierarchy
ValidationTable
└─DecriptionValidationTable
└─FileValidationTable

Source
DDVALTBL.PKG
Usage
use ddvaltbl

Object object_name is a DescriptionValidationTable


set table_title to title
Procedure Fill_list
Send Add_table_value value description itemID
:
end_Procedure
End_Object

Argument Explanation
object_name The name of the DescriptionValidationTable object
title An optional text to describe or explain the list as a whole
value A value to use for validation or prompting
description Descriptive text to be presented with value to explain its meaning
itemID An optional Integer value by means of which to identify and/or
sort list items independently of their values or descriptions.
Of Special Note
This is an object for assignment in DataDictionarys to database fields with the
field_value_table property. It provides both values for insertion into the database and
descriptions to explain each value. It is the superclass of a hierarchy of more-capable and
-complex validation classes, but is usable in its own right in simple, static situations.

-161-
DataFlex 3.2 Data Dictionary Guide

If the validate_state property is set false, entries are permitted that are not in the list; in
its default true state, it requires an entry that matches one of the existing table items. If
the static_state property is set false, the fill_list procedure will be sent every time the
table is activated; in its default true state, the object is loaded with its list only once in
each session.
Properties
This class's properties are unchanged from those of its superclass.
Methods

Normal Interface

add_table_value string value string description integer itemID — procedure

This message should be sent for each value and description you desire to have in your
validation table. The messages should be sent in the order in which you wish to have
values be presented in the list. The last two arguments are optional. ItemID would
typically be the number of the record in the source database file from which each item’s
data is drawn.

FileValidationTable

Purpose
To provide a three-column table of validation data drawn from a database file for
validation lists used through the field_value_table field property in DataDictionary
objects.
Hierarchy
DescriptionValidationTable
└─FileValidationTable
└─CodeValdiationTable

Source
DDVALTBL.PKG
Usage
use ddvaltbl

Object object_name is a FileValidationTable


-162-
DataFlex 3.2 Data Dictionary Guide

set table_title to title


Set Main_File to file
Set Code_Field to value_field
Set Description_field to description_field
Set Ordering to index
End_Object

Argument Explanation
object_name The name of the FileValidationTable object
title An optional text to describe or explain the list as a whole
file The number of the file that contains the data to be
presented and used by this object
value_field The number of the field in file that contains the value to
use for validation or prompting
description_field The number of the field in file that contains descriptive
text to be presented with value to explain its meaning
index The number of the index of file by which to order the
records containing the values and descriptions.
Of Special Note
This is an object for assignment in DataDictionarys to database fields with the
field_value_table property. It provides both values for insertion into the database and
descriptions to explain each value. It draws its data from up to two fields of a database file
identified in the definition of the object. Also specified in the object definition is the index
of the database file by which to order the presentation of the values and descriptions.

If the validate_state property is set false, entries are permitted that are not in the list; in
its default true state, it requires an entry that matches one of the existing table items. If
the static_state property is set false, the fill_list procedure will be sent every time the
table is activated; in its default true state, the object is loaded with its list only once in
each session.
Properties

Normal Interface

code_field — integer — 1 — value_field

This identifies the field in the main_file from which the values are to be drawn for
validation and insertion into the database.

-163-
DataFlex 3.2 Data Dictionary Guide

description_field — integer — 2 — description_field

This identifies the field in the main_file from which the descriptions are to be drawn that
explain (and possibly sort) the values for validation and insertion into the database.

main_file — integer — file

This identifies the main_file from which the values are to be drawn for validation and
insertion into the database and the descriptions that explain (and possibly sort) them.

ordering — integer — 1 — index

This identifies the index of the main_file by which the values for validation and insertion
into the database and their descriptions are to be ordered in this object. This index might
be based on the code_field, the description_field, or others.
Methods

Advanced Interface

fill_list — procedure

Fills the object list from the main_file. Sent when the object is loaded and, if static_state
is false, refills the list in the same manner every time it is used for a validation.

CodeValidationTable

Purpose
To provide a three-column table of validation data drawn from the central codes database
file for validation lists used through the field_value_table field property in DataDictionary
objects.
Hierarchy
FileValidationTable
└─CodeValidationTable

Source
DDVALTBL.PKG
-164-
DataFlex 3.2 Data Dictionary Guide

Sample
Object Ship_table is a CodeValidationTable
Set Validate_State to False
Set Type_Value to "SHIPPING"
Set Static_State to TRUE
Set No_Fill_State to TRUE
Set Allow_Blank_State to True
End_Object
:
Class OrderHea_Data_Set is a DataDictionary
:
Procedure define_fields
:
Set Field_Value_Table field OrderHea.Via to ;
(Ship_Table(Current_Object))

Usage
use ddvaltbl

Object object_name is a CodeValidationTable


set table_title to title
Set type_value to type
End_Object

Argument Explanation
object_name The name of the CodeValidationTable object
title An optional text to describe or explain the list as a whole
type The constraining value common to all value/description records
that it is desired to use in object_name.
Of Special Note
This is an object for assignment in DataDictionarys to database fields with the
field_value_table property. It provides both values for insertion into the database and
descriptions to explain each value. It draws its data from up to two fields of a central
codes database file, by default one named CODEMAST. This file contains, along with the
value and description fields (known by default to all objects of this class), a field for type
values by which to group value/description records for selection for all the (possibly
unrelated) validation fields in an application, and an index that orders the records both for
this selection and for their presentation in all the application’s objects of this class.
If the validate_state property is set false, entries are permitted that are not in the list; in
its default true state, it requires an entry that matches one of the existing table items. If
the static_state property is set false, the fill_list procedure will be sent every time the

-165-
DataFlex 3.2 Data Dictionary Guide

table is activated; in its default true state, the object is loaded with its list only once in
each session.
Properties

Normal Interface

type_value — string — type

This sets the value in the type_field by which records containing the values for validation
and insertion into the database and their accompanying descriptions are selected for this
object.

Advanced Interface

type_field — integer — 1 — field

This identifies the field in CODEMAST that contains the type values by which records
containing the values for validation and insertion into the database and their
accompanying descriptions are selected for all objects of this class by default. The
ordering index is based on the value of this field followed by the value of the code_field.
Methods
This class's procedures and functions are unchanged from those of its superclass.
ValidationList

Purpose
To provide a default interface object for validation tables used as prompt objects. This is
used through field properties in DataDictionary objects.
Hierarchy
Edit
└─ValidationList

Source
DDPCKLST.PKG
Usage.
use ddpcklst
-166-
DataFlex 3.2 Data Dictionary Guide

Object object_name is a ValidationList


End_Object

Argument Explanation
object_name The name of the ValidationList object
Of Special Note
When identified as the prompt object for a field (in a DataDictionary) or an item in a
DEO, an object of this class automatically provides a popup list of valid database values,
by default from the field (to which the DEO item is attached). The usage shown above is
the minimal usage that will provide that and all other default behaviors. Below is the
syntax of more-advanced usage:

Object object_name is a ValidationList // defaults underlined


Set sort_state to {True| False}
Set Code_Display_mode to {CD_Code_Display_Code |
CD_Code_Display_Description |
CD_Code_Display_Both | -1} // -1 = auto assign
Set Static_State to True| False
Set Table_Title to title|"" // ""=auto assign
Set Auto_Size_state to True| False // windows only

// allows you to create any kind of description you want


Function Code_Description_value string description ;
string code returns string
:
End_Function

End_Object

Properties

Normal Interface

auto_size_state — boolean — true| false

If this property is true, this object sizes itself to accommodate the code_display_mode
automatically.

-167-
DataFlex 3.2 Data Dictionary Guide

code_display_mode — integer — -1| CD_Code_Display_Code|


CD_Code_Display_Description| CD_Code_Display_Both

This property specifies whether the list will display the choices’ codes, descriptions, or
both. If it is set to -1, the mode is “auto-assign,” which means it will be governed in each
DEO according to the setting of the item’s code_description_export_state.

table_title — string — “”| title

A null value for this property specifies “auto-assign,” which uses the Table_Title of the
File_Field_Table_Object, if any, of the field. If there is none, the system default data-
dictionary grid title is used. If title is other than null, that is used as the title of this object.
Methods

Normal Interface

code_description_value string description string code returns string — function

This is a “hook” function that enables you to perform any processing on, or even
substitution for, the description that displays with or for each code.

BusinessProcess

Purpose
To contain and execute the statements to perform a batch process on an application’s
database files, together with the data dictionaries containing the business rules applicable
to the process.
Hierarchy
VConsole
└─BusinessProcess
Source
BATCHDD.PKG
Sample
This sample batch process creates ten test customers. The process cannot be
interrupted. If an error occurs during the save, an error message will be displayed and the
process will stop.

-168-
DataFlex 3.2 Data Dictionary Guide

Object CreateCustomers is a BusinessProcess

Set Process_Title To "Let's add some test customers"

Object Customer_DD is a Customer_DataDictionary


End_Object

Procedure onProcess
Local Integer Server# NotOK
Move (Customer_DD(Current_Object)) to Server#
For I from 1 to 10
Send Update_Status ("Adding Test Customer #" *String(i) *"of 10"))
Send Clear to Server#
// add any data we need into our DD Buffer
Set Field_Changed_Value of Server# FIELD Customer.Name to "Test"
Set Field_Changed_Value of Server# FIELD Customer.Etc to "Etc."
Get Request_Validate of Server# to NotOk
If NotOk Procedure_Return
Get Request_Save to Server#
If (Err) Procedure_Return
Loop
End_Procedure

End_Object

Syntax
Filename.bp file:

Object name is a BusinessProcess


//Set properties
:
//Create process’s DDO structure
:
Procedure onProcess
:
End_Procedure
End_Object

End of file filename.bp

Filename.vw file:

Object rptName is a ReportView


:
#Include filename.bp // include the batch-process plug-in name

-169-
DataFlex 3.2 Data Dictionary Guide

//User-interface object

Procedure DoIt // assume some button sends this


Send doProcess to (name(Current_Object))
End_Procedure
End_Object

End of file filename.vw

BPOs can also be added to normal views to handle special batch-update conditions. Just
plug in the BP and send onProcess to it.

Object viewName is a dbView


#Include filename.bp // include batch-process plug-in name

Procedure DoIt // assume some button starts this


Send doProcess to (name(Current_Object))
End_Procedure
:
//Create view’s DDO structure
:
//Create DEOs
:
End_Object

Of Special Note
You create a business process exactly like you create a report view. The business
process is just a different type of plug-in. Business processes automatically support status
panels (which optionally support cancellation) and error redirection handling (during
processing, all errors are redirected to the BusinessProcess object). BPOs also support a
message protocol for logging process activity.

A BPO consists of a non-visual object that contains a DDO structure and the logic to run
the process. Normally a process is called by sending the message DoProcess. This is a
predefined message that intializes the object (start_process), sends the event message
onProcess, and then closes the process (end_process).

The heart of the process is the onProcess procedure. It is the main processing loop. By
default it does nothing and it is expected that you will place your process code in this
procedure. You should try to process all database activity through the DDO structure. To

-170-
DataFlex 3.2 Data Dictionary Guide

do this, you must send messages to the appropriate DDO. These messages will most-
likely include:

• Clearing: Send Clear or Clear_all


• Finding: Send Find (new message in DD), request_assign, or request_find
• Saving: Get request_validate and send request_save
• Deleting: send Request_Delete
• Field changing: Get/Set Field_Value, Field_Changed_Value, etc.

Validation

By default, request_save does not perform field validation. You must get
Request_Validate to the DDO to perform field validation. Request_save is then sent if
the field validation was OK (returned 0). Note the validate_save is always called as part
of request_save. We separate the field validation from saving because this is a batch
process and you may wish to optimize this process by not performing field validation on
every field in every DDO that is part of the save. We provide the ability to do the
validation, but give you the flexibility to skip it.

Error Handling
During a batch process, all errors are redirected to the BPO. When an error occurs, the
message Error_Report is sent to the BPO. Depending on how several properties are set,
the BPO will handle the error in different ways. If the property display_error_state is
true, the error will get redirected to the standard Visual DataFlex error object, which will
cause the error message to be displayed in a message box. Since you normally do not
want interactive error messages displayed during a batch process, this property defaults
to false. If a status-log object is defined and status_log_state is true, errors will get
logged in the status file. Error_Report does this by sending the message
Error_Status_Log. If status logging is not enabled, the program code could send this
message itself. In addition, the message onError is sent. You can use this to handle
custom errors any way you want. Finally, errors set the err indicator true. You can use
this information within your batch-processing loop to determine how and whether a
process should continue.

Interrupting a Process

Since you control the processing loop, you can control whether and how the process
should be canceled. A message is provided which you may use that will check for a
cancel (from the status panel) or an error (from the error). A complete interface is
provided to support this.
-171-
DataFlex 3.2 Data Dictionary Guide

Status Logging Status logging refers to a defined interface for sending information to a
status-logging object. Various properties and methods are created within BPOs to support
easy status logging. The program must set the property Status_log_Id to the object ID of
the status-log object. It can then set the property Status_log_State to true. When true,
a log entry is sent when a BPO process is started, a BPO process is ended, and when an
error occurs. Additional status lines can be sent by sending the message log_status
passing the text to be logged.

The actual interface to the status-log object consists of two public messages: Log_Status
and Log_Clear. It is the status-log object’s responsibility to do something useful with
these messages. The prototype log object provided with Visual DataFlex (found in
StatLog.pkg and StatFLog.pkg) writes a log entry consisting of date, time, and comment
to a simple data file. It is expected that you may wish to expand upon this logging
process by extending the data file (e.g., adding a user name), its indexes, by moving the
log file to another file-list entry, or by expanding the interface (e.g., add ability to review
the log, sort by user name). The log object was purposely kept simple. It does however
provide basic multi-user logging.

Properties
allow_cancel_state — boolean — true| false

Specifies whether the status panel will support a Cancel button. When false, the status
panel is used only to show progress.

display_error_state — boolean — true| false

This specifies whether an error should be sent to the standard error-handler object,
causing the error to be presented in a pop-up message box. Normally, you would not want
this during a batch process.

error_check_state — boolean — true| false

Set true by the batch object's error handler. This is used by the cancel checker to
possibly warn of an error and allow an exit.

error_count — integer — number_of_errors

-172-
DataFlex 3.2 Data Dictionary Guide

Keeps track of errors encountered during process. Developers can query this to see how
many errors occurred during a process. This is usually not set.

old_error_object_id — integer — object_id

When the process is started, the error handler is redirected to the batch object. You can
find the old error handler (usually the primary error object) with this property. This can be
used to redirect errors to this handler (which is what happens if display_error_state is
true).

process_caption — string — Running Process — text

Caption-bar text for status panel (see status-panel docs)

process_message — string — text

Message that appears in status panel (see status-panel docs)

process_title — string — text

Title that appears in status panel (see status-panel docs)

status_log_id — integer — object_id

Object ID of status-log object. When Log_Status is sent, it directs the message to


status_log_ID. If this ID is zero, status logging will be ignored. (All status logging goes
through the message Log_Status. Log_Status checks the value of this property. If non-
zero, it sends the message Log_Status to the status-object ID. If zero, it does nothing.)
It is your responsibility to include a status-log object in your program (you can use the one
provided in StatLog.pkg as an example) and to assign the status object’s ID to this
property.
Use StatLog.pkg // creates object named Status_Log
:
:
Object xxxx is a BusinessProcess
Set Status_Log_Id to (Status_Log(Current_Object))
Set Status_Log_State to TRUE
:

status_log_state — boolean — true| false

-173-
DataFlex 3.2 Data Dictionary Guide

Set this property true if you want automatic status logging (to status-log object) to occur
when process starts, stops, and when an error occurs.
This property only affects automatic logging (start process, stop process, and error
logging). The program can log messages at any time by sending the messages
status_log, start_log, stop_log and error_log_status.

status_panel_state — boolean — true| false

Determines if a status panel should be presented. When true, a panel appears when the
process starts and is removed when the process is complete.
Events
OnError integer error_info string errMsg — procedure

This does nothing by default and is provided as a hook to handle custom error reporting.
This message is designed for augmentation and should never be sent. It is sent whenever
an error occurs (it is sent by Error_report.). The variable Error_Info is a complex value
where hi(Error_info) is the error number and low(error_info) is the error line number.
This message is sent by error_report (which is itself called anytime an error occurs). If
you study error_report, you will see that this procedure might have already logged the
error in a status log (if status_log_state is true) and might have reported the error in a
message box (if display_error_state is true). Often these options will be all that is
required and there will be no need to augment this message. If status_log_state is false
and display_error_state is false (both of these are the defaults), then no error
processing has occurred and you may wish to augment this procedure to handle an error.

OnProcess — procedure

Create this procedure. This is where you put your processing code. At this point, your
status panel (if any) is visible and you are ready to process.
Methods

Normal Interface

cancel_check returns integer — function

Get this to determine whether the process should be interrupted. It can be interrupted by
the status panel (cancel) or by an error. If a cancel or error condition exists, it figures out
what to do by calling process_interrupt. You are expected to call this message, not to
-174-
DataFlex 3.2 Data Dictionary Guide

augment it. It returns non-zero for a cancel. You can call this function anytime you need to
determine if the process should be halted.
Procedure onProcess
:
Repeat
:
// find record and do the process
:
Get Cancel_check to StopIt
If StopIt procedure_Return
:
Loop
End_Procedure

doProcess — procedure

This is the primary external interface into this object. This starts the batch process. It calls
start_Process, calls onProcess, and calls End_Process. Usually you do not need to
augment this. You can augment onProcess.

end_log — procedure

Sends an end-log message to the log object. It calls Log_Status passing status title plus
the number of errors encountered. Sent by End_Process. Good for augmentation.

end_process — procedure

Ends the batch process. Removes the status panel if required. Sends close message to
log if required. Good for augmentation (please forward). This is sent by DoProcess, so
you usually do not need to send this message.

end_status — procedure

Ends the status panel. Sent from various places. Anytime you need to do any type of
input, you must make sure you end the status panel. It can always be restarted with
resume_status

error_log_status integer error_info string errMsg — procedure

Called by error_report if status_log_state is true. By default it sends the message


log_status, passing a string consisting of Error: + Error Number + Error Message. This

-175-
DataFlex 3.2 Data Dictionary Guide

message can also be sended. For example, you may augment onError to send this
message when status_log_state is false.
Procedure onError integer Error_Info String ErrMsg
send Error_Log_Status Error_info ErrMsg
End_procedure

The variable Error_Info is a complex Integer where hi(Error_info) is the error number
and low(error_info) is the error line number.

error_report integer error_info string errMsg — procedure

Sent when an error occurs. If status_log_state is true, it will log this message by sending
the message error_log_status. If display_error_state is true, it will send this message
to the global error object, which will cause an error-message box to appear (normally you
will not want this and that property is, by default, false). This procedure will always send
the message onError.

This message should never be sent and will rarely be augmented. Behaviors can be
modified by setting the properties Status_log_state, display_error_state and augmenting
the event message onError.

The variable Error_Info is a complex Integer where hi(Error_info) is the error number
and low(error_info) is the error line number.

log_status string message — procedure

Sends passed message to log object. Good for sending. All status messages go through
this procedure here. By default this message finds the object ID of the status-log object,
and, if found, sends the same message on to that object.

Because all log messages pass through this procedure, this message can be used to
customize or disable any logging process.

process_interrupt returns integer — function

Called by Cancel_Check if a user response is required to determine if a process should


be canceled. It is expected that the function will present some kind of interface object
(like a message box) and ask users if they wish to cancel. By default it presents a
message box informing user that either the Cancel key was pressed or an error occurred
and asking if the process should be halted. It returns non-zero to cancel. To be
augmented and not called.
-176-
DataFlex 3.2 Data Dictionary Guide

resume_status — procedure

Resumes a status panel that has been stopped. For example, the error handler will
remove the panel before popping up the error and then put it back up. This will normally
not be augmented. It may be sent by the program to remove the status panel (send
end_status) temporarily and to then restore it.

start_log — procedure

Sends a start-log message to the log object. It calls Log_Status passing Start process:
plus the name of the process (status title). Sent by Start_Process. Good for
augmentation.

start_process — procedure

Starts the batch process. Intializes and displays the status panel if required. Initializes log
if required. Zeros the error_count. Good for augmentation (please forward). This is sent
by DoProcess, so you usually do not need to send this message.

start_status — procedure

Starts the status panel. This is normally sent by Start_Process and is therefore normally
not sent or augmented by the developer.

update_status string chars — procedure

Can be sent to update a status panel's progress. Pass it any displayable characters.

StatusPanel

Purpose
To support a visual object to displayed by long-running processes that may be unattended
(batch processes) to report errors that arise in the job, the proportion to which the job is
complete from time to time, and other information of potential interest to users running
such jobs. This class supports the display of “host/sentinel” monitoring.

-177-
DataFlex 3.2 Data Dictionary Guide

Hierarchy
Message
└─StatusPanel
Source
STPNL_CM.PKG
Syntax
Use SttPnl_cm.pkg

An object of this class named Status_panel is instantiated automatically by any program


that uses its package. The object’s behaviors are controlled entirely by messages sent to
it.
Usage
:
Procedure theProcess
Move (Status_Panel(Current_Object)) to StatPnl
Send Initialize_StatusPanel to StatPnl aCaption aTitle aMessage
Send Start_StatusPanel to StatPnl
Repeat
: //process batch item(s)
Send Update_StatusPanel to StatPnl aProgressString
Get Check_StatusPanel of StatPnl to userCancel
:
Until (done or userCancel)
Send Stop_StatusPanel to StatPnl
:
End_procedure
:

Of Special Note
The status panel is used to create an interruptible progress dialog to be used during
modal processes like report and batch processes. The panel is defined by setting the
contents of several displayed areas:

Caption bar the value in the caption bar


Title a centered title that appears inside the dialog
Message a longer message that appears below the title
Action an area below that message that is used to display progress.
Button a Cancel button that appears below the display

The panel is invoked by running a "sentinel" program that passes data back and forth
between the modal process and the status panel. Because the panel and the process are
-178-
DataFlex 3.2 Data Dictionary Guide

separate processes, the monitored process can run at a very fast speed without the
delays imposed by maintaining a display.
Properties
All the properties of this class are defined and set in the class. They cannot be changed in
programs except by sending messages (see below) to the object.
Methods

Normal Interface

Check_StatusPanel returns integer

This returns a status value from the status panel. Normally a non-zero return value
means that the process has been canceled.

Initialize_StatusPanel string caption string title string message — procedure

This sets the values of the popup-status-panel elements where:

Caption is the content of the caption bar


Title is a centered title that appears in the dialog
Message is a longer message that can appear below the title

This should be done before the status panel is activated. This data should be
considered static. Once the status panel has popped up, these characteristics will not
change. Note: If the strings are very long, they may not all fit within a single command
line. You can also set these values individually by sending Set Caption_text, Set
Title_Text, and Set Message_Text.

Start_StatusPanel — procedure

This starts the status panel process.

Stop_StatusPanel — procedure

This stops the status popup and restores the current program’s normal modality. This
must be sent at the end of the process.

Update_StatusPanel string text — procedure

-179-
DataFlex 3.2 Data Dictionary Guide

This places a value in the "action window" of an active status panel. This is where the
progress information is added. Each text replaces the one that was sent before it.
Send Update_StatusPanel to (Status_Panel(current_object)) ;
reccount “ records processed”

Advanced Interface

Action_text returns string — function

This display value is normally changed, at regular intervals, via the Update_StatusPanel
message

Button_text returns string — function

This display value is not normally changed after the object is initialized, but it can be.

Caption_text returns string — function

This display value is not normally changed after the object is initialized, but it can be.

Message_text returns string — function

This display value is not normally changed after the object is initialized, but it can be.

Sentinel_Name returns string — function

This sets the name of the sentinel program used. Normally this will be the default
sentinel so no change will be required.

Title_text returns string — function

This display value is not normally changed after the object is initialized, but it can be.

-180-
DataFlex 3.2 Data Dictionary Guide

StatusdbLog

Purpose
To define a global object used for logging status and error reports from unattended
(batch) processes to a database file.
Hierarchy
VConsole
└─StatusdbLog
Source
STATFLOG.PKG
(STATALOG.PKG creates a class that outputs log entries to an ASCII file)
Syntax
Objects of this class are instantiated by useing the STATLOG.PKG file in a program. The
resultant global status-log object is named status_log and can be placed in use simply by
setting the status_log_id property of the object requiring its services (a business process
or report) to the value of that object by name.
Use StatLog.pkg
:
object name is a {businessProcess| basicReport}
Set Status_log_id to (Status_Log(current_Object))

Use of this class for subclassing to create custom status-log capabilities is encouraged.
The provided class is quite rudimentary, and is intended to be used as a framework on
which you can build your desired functionalities as extensions. Direct instantiation of this
class or any subclass of it is not encouraged. The STATLOG.PKG file should be used.
Of Special Note
Objects of this class output to a database file named STATLOG. Its definition is listed
below. Note that this may be added as any entry within your file list and that this is a
minimum specification for this file. You may wish to add additional fields and indexes. You
must create this file and its file-list entry before this object can perform its intended
function.

-----------------------------------------------------------------------------
DATE: 07/22/1997 TIME: 16:07 PAGE: 1
FILE DEFINITION FOR FILE: STATLOG (# 19)
-----------------------------------------------------------------------------
DRIVER NAME : DATAFLEX
FILE ROOT NAME : StatLog
USER DISPLAY NAME : StatLog
-181-
DataFlex 3.2 Data Dictionary Guide

DATAFLEX FILE NAME : STATLOG


-----------------------------------------------------------------------------
RECORD LENGTH : 128 ( USED: 108 )
MAX NUMBER OF RECORDS : 10000 ( USED: 27 )
FILE COMPRESSION : NONE
RE-USE DELETED SPACE : YES
LOCKING TYPE : FILE
HEADER INTEGRITY CHECKING : YES
TRANSACTION TYPE : CLIENT ATOMIC
RECORD IDENTITY INDEX : 0 ( 0 , 0 )
FILE LOGIN PARAMETER :
SYSTEM FILE : NO
-----------------------------------------------------------------------------

NUM FIELD NAME TYPE SIZE OFFST IX RELATES TO FILE.FIELD


--- --------------- ---- ----- ----- -- ---------------------------------
1 DATE DAT 6 1
2 TIME ASC 5 4
3 DESCRIPTION ASC 100 9

Events
OnNewRecord — procedure

This is called before the actual save but after the status text and date/time stamp have
been moved to the database. It does nothing by default and should be used for
augmentation. If you added extra fields to your database, you could set those fields’
values in this procedure
Methods

Normal Interface

log_clear — procedure

This removes all records from the STATLOG file..

log_status string text — procedure

This creates a new record in the status-log file. It sets the following database values:

Statlog.Description text
Statlog.Date Current date
Statlog.Time Current time in HH:MM string format

-182-
DataFlex 3.2 Data Dictionary Guide

It also sends the message onNewRecord. This is called after the information has been
moved to the buffer but before the save. You can use this hook to customize the record
data before the save.

During the execution of this procedure, the error handler is temporarily set to this object. If
an error occurs inside this procedure, the error will be ignored. This was done to prevent
recursion. Often status logging is used to record errors.

-183-

Você também pode gostar