Informix
4gl
sample application
with Axional Studio
. The application CUSTOMER can select, modify and create new customers.
1 Stores 7 4GL application
1.1 Using 4GL application
The following example shows how to make a customers query from California state.



1.2 Forms development with 4GL
Customer application allows to query and manage customers. It contains two files:
- custform.per - to perform the QBE query and to display customer data.
- d4_cust.4gl - to perform the query and data management processing on the cursor data.
1.2.1 Customer query and management form
The query by example (QBE) and the cursor with resulting data can be viewed using the custform.per.
And it's defined in custform.per file.
DATABASE stores7 SCREEN { Customer Form Number :[f000 ] Owner Name :[f001 ][f002 ] Company :[f003 ] Address :[f004 ] [f005 ] City :[f006 ] State:[a0] Zipcode:[f007 ] Telephone :[f008 ] } TABLES customer ATTRIBUTES f000 = customer.customer_num, NOENTRY; f001 = customer.fname; f002 = customer.lname; f003 = customer.company; f004 = customer.address1; f005 = customer.address2; f006 = customer.city; a0 = customer.state, UPSHIFT; f007 = customer.zipcode; f008 = customer.phone, PICTURE = "###-###-#### XXXXX";
1.2.2 d4_cust.4gl
The following 4gl
application is used to manage customer form actions, including query, add, update or delete a customer.
GLOBALS "d4_globals.4gl" FUNCTION customer() OPTIONS FORM LINE 7 OPEN FORM customer FROM "custform" DISPLAY FORM customer ATTRIBUTE(MAGENTA) CALL ring_menu() CALL fgl_drawbox(3,32,3,42) CALL fgl_drawbox(3,61,8,7) CALL fgl_drawbox(11,61,8,7) LET p_customer.customer_num = NULL MENU "CUSTOMER" COMMAND "One-add" "Add a new customer to the database" HELP 201 CALL unring_menu() CALL add_customer(FALSE) call ring_menu () COMMAND "Many-add" "Add several new customers to database" HELP 202 CALL unring_menu() CALL add_customer(TRUE) call ring_menu () COMMAND "Find-cust" "Look up specific customer" HELP 203 call unring_menu () IF query_customer(23) THEN call ring_menu () NEXT OPTION "Update-cust" END IF call ring_menu () COMMAND "Update-cust" "Modify current customer information" HELP 204 CALL unring_menu() CALL update_customer() call ring_menu () NEXT OPTION "Find-cust" COMMAND "Delete-cust" "Remove a customer from database" HELP 205 CALL unring_menu() CALL delete_customer() call ring_menu () NEXT OPTION "Find-cust" COMMAND "Exit" "Return to MAIN Menu" HELP 206 CLEAR SCREEN EXIT MENU END MENU OPTIONS FORM LINE 3 END FUNCTION FUNCTION add_customer(repeat) DEFINE repeat INTEGER CALL clear_menu() MESSAGE "Press F1 or CTRL-F for field help; ", "F2 or CTRL-Y to return to menu" IF repeat THEN WHILE input_cust() ERROR "Customer data entered" ATTRIBUTE (GREEN) END WHILE CALL mess("Multiple insert completed - current screen values ignored", 23) ELSE IF input_cust() THEN ERROR "Customer data entered" ATTRIBUTE (GREEN) ELSE CLEAR FORM LET p_customer.customer_num = NULL ERROR "Customer addition aborted" ATTRIBUTE (RED, REVERSE) END IF END IF END FUNCTION FUNCTION input_cust() DISPLAY "Press ESC to enter new customer data" AT 1,1 INPUT BY NAME p_customer.* AFTER FIELD state CALL statehelp() DISPLAY "Press ESC to enter new customer data", "" AT 1,1 ON KEY (F1, CONTROL-F) CALL customer_help() ON KEY (F2, CONTROL-Y) LET int_flag = TRUE EXIT INPUT END INPUT IF int_flag THEN LET int_flag = FALSE RETURN(FALSE) END IF LET p_customer.customer_num = 0 INSERT INTO customer VALUES (p_customer.*) LET p_customer.customer_num = SQLCA.SQLERRD[2] DISPLAY BY NAME p_customer.customer_num ATTRIBUTE(MAGENTA) RETURN(TRUE) END FUNCTION FUNCTION query_customer(mrow) DEFINE where_part CHAR(500), query_text CHAR(500), answer CHAR(1), mrow, chosen, exist SMALLINT CLEAR FORM CALL clear_menu() MESSAGE "Enter criteria for selection" CONSTRUCT where_part ON customer.* FROM customer.* MESSAGE "" IF int_flag THEN LET int_flag = FALSE CLEAR FORM ERROR "Customer query aborted" ATTRIBUTE(RED, REVERSE) LET p_customer.customer_num = NULL RETURN (p_customer.customer_num) END IF LET query_text = "select * from customer where ", where_part CLIPPED, " order by lname" PREPARE statement_1 FROM query_text DECLARE customer_set SCROLL CURSOR FOR statement_1 OPEN customer_set FETCH FIRST customer_set INTO p_customer.* IF status = NOTFOUND THEN LET exist = FALSE ELSE LET exist = TRUE DISPLAY BY NAME p_customer.* ATTRIBUTE(MAGENTA) MENU "BROWSE" COMMAND "Next" "View the next customer in the list" FETCH NEXT customer_set INTO p_customer.* IF status = NOTFOUND THEN ERROR "No more customers in this direction" ATTRIBUTE(RED, REVERSE) FETCH LAST customer_set INTO p_customer.* END IF DISPLAY BY NAME p_customer.* ATTRIBUTE(MAGENTA) COMMAND "Previous" "View the previous customer in the list" FETCH PREVIOUS customer_set INTO p_customer.* IF status = NOTFOUND THEN ERROR "No more customers in this direction" ATTRIBUTE(RED, REVERSE) FETCH FIRST customer_set INTO p_customer.* END IF DISPLAY BY NAME p_customer.* ATTRIBUTE(MAGENTA) COMMAND "First" "View the first customer in the list" FETCH FIRST customer_set INTO p_customer.* DISPLAY BY NAME p_customer.* ATTRIBUTE(MAGENTA) COMMAND "Last" "View the last customer in the list" FETCH LAST customer_set INTO p_customer.* DISPLAY BY NAME p_customer.* ATTRIBUTE(MAGENTA) COMMAND "Select" "Exit BROWSE selecting the current customer" LET chosen = TRUE EXIT MENU COMMAND "Quit" "Quit BROWSE without selecting a customer" LET chosen = FALSE EXIT MENU END MENU END IF CLOSE customer_set CALL clear_menu() IF NOT exist THEN CLEAR FORM CALL mess("No customer satisfies query", mrow) LET p_customer.customer_num = NULL RETURN (FALSE) END IF IF NOT chosen THEN CLEAR FORM LET p_customer.customer_num = NULL CALL mess("No selection made", mrow) RETURN (FALSE) END IF RETURN (TRUE) END FUNCTION FUNCTION update_customer() CALL clear_menu() IF p_customer.customer_num IS NULL THEN ERROR "No customer has been selected; use the Find-cust option" ATTRIBUTE (RED, REVERSE) RETURN END IF MESSAGE "Press F1 or CTRL-F for field-level help" DISPLAY "Press ESC to update customer data; DEL to abort" AT 1,1 INPUT BY NAME p_customer.* WITHOUT DEFAULTS AFTER FIELD state CALL statehelp() DISPLAY "Press ESC to update customer data; DEL to abort", "" AT 1,1 ON KEY (F1, CONTROL-F) CALL customer_help() END INPUT IF NOT int_flag THEN UPDATE customer SET customer.* = p_customer.* WHERE customer_num = p_customer.customer_num CALL mess("Customer data modified", 23) ELSE LET int_flag = FALSE SELECT * INTO p_customer.* FROM customer WHERE customer_num = p_customer.customer_num DISPLAY BY NAME p_customer.* ATTRIBUTE(MAGENTA) ERROR "Customer update aborted" ATTRIBUTE (RED, REVERSE) END IF END FUNCTION FUNCTION delete_customer() DEFINE answer CHAR(1), num_orders INTEGER CALL clear_menu() IF p_customer.customer_num IS NULL THEN ERROR "No customer has been selected; use the Find-cust option" ATTRIBUTE (RED, REVERSE) RETURN END IF SELECT COUNT(*) INTO num_orders FROM orders WHERE customer_num = p_customer.customer_num IF num_orders THEN ERROR "This customer has active orders and can not be removed" ATTRIBUTE (RED, REVERSE) RETURN END IF PROMPT " Are you sure you want to delete this customer row? " FOR CHAR answer IF answer MATCHES "[yY]" THEN DELETE FROM customer WHERE customer_num = p_customer.customer_num CLEAR FORM CALL mess("Customer entry deleted", 23) LET p_customer.customer_num = NULL ELSE ERROR "Deletion aborted" ATTRIBUTE (RED, REVERSE) END IF END FUNCTION FUNCTION customer_help() CASE WHEN infield(customer_num) CALL showhelp(1001) WHEN infield(fname) CALL showhelp(1002) WHEN infield(lname) CALL showhelp(1003) WHEN infield(company) CALL showhelp(1004) WHEN infield(address1) CALL showhelp(1005) WHEN infield(address2) CALL showhelp(1006) WHEN infield(city) CALL showhelp(1007) WHEN infield(state) CALL showhelp(1008) WHEN infield(zipcode) CALL showhelp(1009) WHEN infield(phone) CALL showhelp(1010) END CASE END FUNCTION FUNCTION statehelp() DEFINE idx INTEGER SELECT COUNT(*) INTO idx FROM state WHERE code = p_customer.state IF idx = 1 THEN RETURN END IF DISPLAY "Move cursor using F3, F4, and arrow keys; press ESC to select state" AT 1,1 OPEN WINDOW w_state AT 8,37 WITH FORM "state_list" ATTRIBUTE (BORDER, RED, FORM LINE 2) CALL set_count(state_cnt) DISPLAY ARRAY p_state TO s_state.* LET idx = arr_curr() CLOSE WINDOW w_state LET p_customer.state = p_state[idx].code DISPLAY BY NAME p_customer.state ATTRIBUTE(MAGENTA) RETURN END FUNCTION
2 Stores 7 Axional Example
First, we will see the same application using Axional
Interface.
2.1 Using Axional
As with the 4gl, this example shows how to make a customers query from California state.


2.2 User guide
2.2.1 Query
When application is activated, it shows a QBE form. You can use common QBE command to perform any type of query.

2.2.2 Form
After the query is performed, a cursor with matching data from customer table is shown.

The form, automatically displays a toolbar with control options. These options include the ability to:

customer list view (nº8)
.

customer PDF (nº9)
.
3 Stores 7 Quick development
d4_cust.4gl + custform.per
3.1 Forms development
To create a form object just go to the physical dictionary of tables, where previously the table of the object that you want to create ( customer) has been defined.
At the bottom of the screen you will find the Object Build Button, which will automatically create the customer object.

Before creating it, a window will be shown asking for the database where the object will be created and the type of renders to be used.

Once finished you can check that the form object has been created.

If the object is executed, the query screen...

...and the form screen will appear.

This operation should take less than 5 minutes (including the creation of physical tables).
4 Stores 7 Advanced development
4.1 How to modify form layout
The following example shows how to modify the form layout.
Within the object definition select the button Form layout.

Now you can define the new number of rows and columns that are needed inside the box.

Once you have selected the number of columns and rows, choose the field you need and drag it to the desired position.

When the field is dropped, the position is automatically saved.

Now, excuting again the form, the new layout is shown reflecting the changes.

This would be the result.

Again, this operation should take less than 5 minutes.
4.2 Define a Soft Reference
This example shows how to define a soft reference in the State field.
4.2.1 Implementation
The implementation of Filtering Helper is achieved by adding some settings to the desired table and columns. According to this configuration, the sistem handles to types of helpers:
- Automatic helpers (
Hard Reference
) are created from the database constraints configuration. - Explicit helpers (
Soft Reference
) are defined by dictionary.
4.2.2 Helper definition
The Helper definition form contains all the necessary fields and componenents to define and maintain Filtering helpers. Each helper definition is identified by a table name and a method. The method generally corresponds to table column; it is not necessary but is useful when using automatic statements as we will see bellow.

Autocomplete statement
Each time the user types a character in the input field having an explicit Filtering Helper
the Autocomplete statement is executed and the result of this statement is displayed to the user as an autocomplete list.
This achieved through an automatic SQL autocomplete statement, with table state and method code:
<select> <columns> state.code, state.sname </columns> <from table='state' /> <where> (UPPER (state.code) LIKE UPPER ('%${q}%') OR UPPER (state.sname) LIKE UPPER ('%${q}%')) </where> </select>
If the autocomplete statement is left blank and the method doesn't correspont with a valid column for the table defined in the helper, an SQL Syntax error will occur.
It is important to note the use of the ${q}
clause in the statement; which references the input pattern typed by the user when autocomplete is requested.
Validation statement
The validation statement has two purposes: verify the integrity of the input value and gather some information related to the input value for filling the form with this data.
This purposes are achieved by executing the Validation SQL statement
when the field value changes.
As it happens with the autocomplete statement, leaving the Validation SQL statement
blank entails the system to build an automatic statement using the helper definition table and method.
The SQL validation statement executed for our helper with table state and method code:
<select> <columns> state.code </columns> <from table='state' /> <where> state.code = ${q} </where> </select>
If the validation statement is left blank and the method doesn't correspont with a valid column for the table defined in the helper, an SQL Syntax error will occur.
Validation SQL Statement accepts both native SQL or XSQL syntax, but Axional Studio Functional Roles will only be applied with the XSQL syntax.
Object data selector
Object data selector is enabled by specifying a column in the Help object
box.
If so, the object used as data selector corresponds with the table name identifying the helper.
The defined column references the column of the destionation object to take the value from an place it in the source field.
Optionally, it could be defined a condition that will be added to the where clause of the destination object.
The main difference is that those expressions are literally replaced in the condition to be send as an object condition clause.
In our case there is no condition, but this is a sample of a object data selector condition using variables:
customer.country = '${country}' AND customer.state = 'A'
The main consideration is that alphanumeric variables should be placed between quotes.
This operation has taken 3 minutes.
4.2.3 Define relation
Once having a proper catalog of helpers, it is the time of telling each field what helper will use and configure the relations between the form and the helper.

Column | Description | Value |
Object | Code of form object containing the field to assign the helper | customer |
Source Column | Name of the field to apply the helper | state |
Destiny table | Table identifying the applicable helper. Corresponds with the previously defined table. | state |
Method | Method identifying the applicable helper. Corresponds with the previously defined method. | code |
This operation has taken 2 minutes.
4.3 How to make a form object
Every Axional
application is composed of objects. Objects are defined as a set of transactions
in a special database named dictionary.
A dictionary is a database that contains a collection of tables that allows programmers define application objects.
The basic structure of any Axional
object is composed of:
- input, for the data that will be used to perform the subsequent process
- process, with the SQL or script code that will be applied on data using the previous input
- output, to define the output structure as a form, report, document, etc
The previous three components are mapped to the following Axional
object components.
- The main SQL/XSQL statement, that will produce a resulsting cursor with data
- The input columns or variables, that will be used to filter the main cursor
- The output columns mapping, that will be used to map the output data into the desired render component (form, report, ...)
4.3.1 SQL/XSQL statement

Number | Description |
---|---|
1 | Specify as object code, in this case is customer , on Object section, the name of the table against the other one which user wants to make insertions, modifications and delete registers. |
2 |
It is a short description of the object, it is used in the tabs. If this object is included as another tabs, the default system will show this tag as a link to access the object. You can also use this description as the title of a Box. |
3 | Title or description of the object, which appears at the top of the screen when it is executed. |
4 | Render type |
5 | The functional group, as its name suggests, consists of a classification of the objects through which they can be grouped based on their characteristics and functional properties. |
6 | Select option READ / WRITE on Type section in order to indicate to the system that form can transact against main table of SQL query. |
7 |
Object query is written on XML code and it must be selected some column of the table which user wants to do insertions, modifications and register deleted. |
4.3.2 Inputs
All columns selected on SQL query whom user could filter when he access to the form.
It used to be a subset of all selected section on query.
If it isn't any column defined, form won't have filter page.

Column *
You can use an asterisk to use all the columns for filtering.
4.3.3 Outputs
All columns selected on SQL query that will be shown on execution object.
Automatic Generation
Exit sections will be generated automatically when object is executed for the first time.
Review table name and section
If query is composed with more than one table, it would necessary to review the table name assigned to each section.
4.3.4 Form layout

Insert
To create a form, first click on the insert button.

Select row and columns for boxes
Below is the form editor, which allows you to select the rows and columns that you want to insert the boxes.


Box type
Once you select the number of columns and rows, choose the type of box.
The different types of boxes are displayed on the left side of the form editor screen.
To select it you have to drag it to the desired position.

Select row and columns for fields
The next step is to define the number of rows and columns that are needed inside the box.

Select outputs
As with the selection of the type of boxes, the outputs are dragged to the desired position.

Select fields type
Once all the outputs have been placed, you should define the type of each field.
The selection method is the same as with the box type.

This operation should take less than 10 minutes.