OpenEdge Development: Progress 4GL Handbook
![]() ![]() ![]()
|
Using Basic 4GL ConstructsIn "Introducing the Progress 4GL," you learned some of the basic characteristics of the Progress 4GL and created a small test procedure. In this chapter you will extend your test procedure by:
Refining the data selection with a WHERE clause
So far you’ve been selecting all the Customer records in the database. Now you’ll refine that selection to show only those Customers from the state of New Hampshire. There is a State field in the Customer table that holds the two-letter state abbreviation for states in the USA.
The Progress 4GL supports a
WHEREclause in any statement that retrieves data from the database, which will be familiar to you if you have used SQL or other similar data access languages. TheWHEREkeyword can be followed by any expression that identifies a subset of the data. You’ll learn a lot more about this in later chapters, but for now a simple expression is all you need.To refine the data selection in your test procedure:
- Add the following
WHEREclause to the end of yourFOR EACHstatement:
- Press F2 to see the reduced list of Customers. The list should now use only a bit more than a page.
- Add a sort expression to the end of your
WHEREclause to sort the Customers in order by their City. The 4GL uses the keywordBYto indicate a sort sequence:
- Press F2 to run the procedure again to see the effects of your change.
Comparison operators
The equal sign is just one of a number of comparison operators you can use in 4GL expressions. Table 2–1 provides a complete list.
Using quotation marks
You can use single quotation marks (‘:) and double quotation marks (“) interchangeably to define a string constant. You must balance them properly, using the same type of quotation mark at the beginning and the end of the string. Use double quotes if your string contains a single quote, and vice versa, as in the following example:
DISPLAY “Always using the same type of quotes!”.DISPLAY ‘:Like this.’.DISPLAY “But never like this!’.
Creating nested blocks to display related data
To review, the
FOR EACHstatement in your procedure creates a code block nested inside the implicit main block of the procedure itself. Now you will create yet another block nested inside of that, to display the Order records in the database for each New Hampshire Customer.To create a nested block, add another
FOR EACHblock inside the one you have, so that your procedure looks like this:
FOR EACH Customer WHERE State = “NH” BY City:DISPLAY CustNum Name City.FOR EACH Order OF Customer:DISPLAY OrderNum OrderDate ShipDate.END.END.
This example shows the code indented so that the new block is visually nested in the outer block, which helps code readability. The intelligent editor should help you with this; if it doesn’t get it quite right, make the effort to indent the code properly yourself.
First, look at the new
FOR EACHstatement. The keywordOFis a shorthand for aWHEREclause that joins the two tables together. When you looked at the two tables and their fields in the Dictionary, you saw that both tables have a CustNum field. This is the primary key of the Customer table, which means that each Customer is assigned a unique number for the CustNum field, and this is the primary identifier for the Customer. In the Order table, the OrderNum is the unique Order identifier, and its primary key. The CustNum field in the Order table points back to the Customer the Order is for. It’s a foreign key because it points to a record in another table. To retrieve and display the Orders for a Customer, you have to join the two tables on the CustNum field that they have in common. The fullWHEREclause for this join would be:WHERE Customer.CustNum = Order.CustNum. This kind of syntax will be familiar to you if you’ve ever worked with SQL.The
WHEREclause is telling Progress to select those records where the CustNum field in one table matches the CustNum field in the other. In order to tell Progress which field is which, both are qualified by the table name, followed by a period.In the Progress 4GL, you can use the syntax
Order OF Customeras a shorthand for this join if the two tables have one or more like-named fields in common that constitute the join relationship, and those fields are indexed in at least one of the tables (normally they should be indexed in both). You can always use the fullWHEREclause syntax instead of theOFphrase if you wish; the effect is the same, and if there is any doubt as to how the tables are related, it makes the relationship your code is using completely clear. In fact, theOFphrase is really one of those beginner shortcuts that makes it easy to write a very simple procedure but which really isn’t good practice in a complex application, because it isn’t clear just from reading the statement which fields are being used to relate the two tables. You should generally be explicit about your field relationships in your applications.These simple nested
FOR EACHstatements accomplish something that would be a lot of work in other languages. To retrieve the Customers and their Orders separately, as you really want to do, you would have to define two separate queries using embedded SQL syntax, open them, and control them explicitly in your code. This would be a lot of work. For example, the straight forward single SQL query to retrieve the same data would be:
SELECT Customer.CustNum, Name, City, OrderNum, OrderData, ShipDate FROM Customer, ORDER WHERE State = “NH” AND Customer.CustNum = Order.CustNum;
This code would retrieve all the related Customers and Orders into a single two-dimensional table, which is not very useful: all the Customer information would be repeated for each of the Customer’s Orders, and you would have to pull it apart yourself to display the information as header and detail, which is probably what you want.
By contrast, when you run your very simple Progress 4GL procedure, you get a default display that represents the data properly as master (Customer) and detail (Order) information, as shown in Figure 2–1.
Figure 2–1: Result of running simple sample procedure
![]()
Progress automatically gives you two separate display areas, one for the Customer fields showing one Customer at a time, and one for the Orders of the Customer. These display areas are called frames. You’ll learn more about Progress frames in later chapters.
Unlike in the first example, which displays a whole page of Customers, each time you press the SPACE BAR, Progress displays just the next Customer and its Orders. Why did Progress do this? The nested
FOR EACHblocks tell Progress that there are multiple Orders to display for each Customer, so it knows that it doesn’t make sense to display more than one Customer at a time. So it creates a small frame just big enough to display the fields for one Customer, and then separately creates another frame where it can display multiple Orders. The latter frame is called a down frame, because it can display multiple rows of data as it moves down the page. The top frame is actually referred to as a one down frame because it displays only a single row of data at a time.You can control the size of the frames, how many rows are displayed, and many other attributes, by appending a
WITHphrase to your statement.To see how the
WITHphrase can affect your test procedure:
- Add the words
WITH CENTEREDto theDISPLAYstatement for the Order frame:
FOR EACH Customer WHERE State = “NH” BY City:DISPLAY CustNum Name City.FOR EACH Order OF Customer:DISPLAY OrderNum OrderDate ShipDateWITH CENTERED.END.END.- Run the procedure again. The Order frame is centered in the default display window:
![]()
There are lots of frame attributes you can specify here (for a description of them, read the section on the
Frame Phrasein the OpenEdge Development: Progress 4GL Reference). This book doesn’t tell you much more about them, either now or later, because you won’t use most of them in your GUI applications. These attributes are designed to help you define frames for a character mode application, where the interface is basically just a series of 24 or 25 lines of 80 characters each. For this kind of display format, a sequence of frames displayed one beneath the other is an appropriate and convenient way to lay out the screen. But in a GUI application, you instead lay out your display using a visual design tool, such as the OpenEdge AppBuilder, and it generates the code or data needed to create the user interface at run time. So this is another part of the snowplow exercise: this chapter shows you the basics of how the 4GL works and how it was designed, even though you will do most of your work a different way in your new applications.Changing labels and formats
The default label for the Order Number field is Order Num (you define default labels in the Data Dictionary when you set up your database), and you might prefer that it just say Order. Also, the default display format for the ShipDate field is different from the format for the OrderDate field: one has a four-digit year and the other a two-digit year. You can change labels and default formats in your
DISPLAYstatement. If you add theLABELkeyword or theFORMATkeyword after the field name, followed by a string for the value you’d prefer, then the display changes accordingly.To make such changes to your test procedure, change the OrderNum
LABELto Order and the ShipDateFORMATto 99/99/99.In the following example, each field has its own line in the code block, to make the code easier to read, and to emphasize doing that doesn’t change how the procedure works. Everything up to the period is one 4GL statement:
FOR EACH Customer WHERE State = "NH" BY City:DISPLAY CustNum NAME City.FOR EACH Order OF Customer:DISPLAY OrderNumLABEL "Order"OrderDateShipDateFORMAT "99/99/99"WITH CENTERED.END.END.
To view the results of these changes, Run your test procedure again:
![]()
Using program variables and data types
Like most programming languages, the Progress 4GL lets you define program variables for use within a procedure. Here is the basic syntax:
In this syntax,
varnameis the name of the variable, which must conform to the same rules as other names in the 4GL. (See the "Variable naming conventions" for details.)Progress supports a range of data types. Table 2–2 lists the basic ones. There are some other special data types available for more advanced programming, but these are enough to get you started.
Here are a few notes on Progress data types:
- All
CHARACTERdata in Progress variables, and in database fields in an OpenEdge database, is stored as variable length strings. You do not need to define the length of a variable, only its display format, which indicates how many characters (at most) are displayed to the user. The default display length forCHARACTERfields is 8 characters. The X symbol represents any printable character, and the 8 in parentheses effectively repeats that character, so that X(8) is the same as XXXXXXXX. The default value for aCHARACTERvariable is the empty string.- You can display dates in a variety of ways, including two- or four-digit years. To get a four-digit year, specify 99/99/9999 as your format. Note that changing the display format for a date does not change how it is stored in the database. Dates are stored in an internal format that can be converted to any of the display formats available to you.
- The
DECIMALdata type supports a total of 50 digits of which up to 10 can be to the right of the decimal point. When you define aDECIMALvariable you can specify the number of positions to the right of the decimal point by adding the qualifierDECIMALS <n>to theDEFINE VARIABLEstatement.- Progress supports the automatic conversion of both
DATEs andDECIMALs to the formats generally used in Europe and other parts of the world outside the US. If you use the European (–E) startup option, then all period or decimal characters inDECIMALformats are converted to commas, and commas are converted to periods. In addition, the defaultDATEdisplay becomes DD/MM/YY or DD/MM/YYYY instead of MM/DD/YY or MM/DD/YYYY.- The
HANDLEdata type is used to store a pointer to a structure that represents a running Progress procedure or an object in a procedure such as a field or button. "Using Dynamic Graphical Objects," and "Using Dynamic Queries and Buffers," provide more information about how to useHANDLEvariables.- The maximum size of an
INTEGERvariable is 2G (slightly over a billion digits).- A
LOGICALvariable represents a yes/no or true/false value. You can specify any pair of literals you wish for the TRUE and FALSE values that are displayed to the user for aLOGICALvariable, with the TRUE or YES value first. However, it is not advisable to useLOGICALs to represent data values that aren’t really logical by nature, but which simply happen to have two valid values, such as Male/Female, because it might be unclear which of those the TRUE value represents.- You will learn about the Progress Unknown value in the "Using the Progress Unknown value" . The default display format for data that has the Unknown value is blank; for other data types it is a question mark.
Defining formats
The list of default formats for different data types introduced you to some of the format characters supported by Progress. Table 2–3 provides a quick summary of the format symbols you’re most likely to use.
You can insert other characters as you wish into formats, and they are displayed as literal values. For example, the
INTEGERvalue 1234 with theFORMAT$>,>>>ABC is displayed as $1,234ABC.Other variable qualifiers
You can qualify a variable definition in a number of ways to modify these defaults. To do this, append one of the keywords listed in Table 2–4 to the end of your variable definition.
:
As an alternative to specifying all of this, you can use the following syntax form to define a variable that is
LIKEanother variable or database field you’ve previously defined:
In this case it inherits the format, label, initial value, and all other attributes of the other variable or field. This is another strength of the Progress 4GL. Your application procedures can inherit many field attributes from the database schema, so that a change to the schema is propagated to all your procedures automatically when they are recompiled. You can also modify those schema defaults in individual procedures.
There’s one more keyword that you should almost always use at the end of your variable definitions, and that is
NO-UNDO. This keyword has to do with how Progress manages transactions that update the database. When you define variables in your 4GL programs, Progress places them into two groups. Those that don’t have theNO-UNDOqualifier are treated as though they were a database record with those variables as fields. If any of the variable values are modified during the course of a database transaction, and then the transaction is backed out, changes to the variable values made during the transaction are backed out as well, so that they revert to their values before the transaction started. This can be very useful sometimes, but in practice, most variables do not need this special treatment, and because Progress has to do some extra work to manage them, it is more efficient to get into the habit of appendingNO-UNDOto the end of your variable definitions unless the variable is one that should be treated as part of a transaction. This places them into a second group where Progress manages them without the transaction support.Variable naming conventions
There are no specific naming requirements for variables, but there are some recommended guidelines that will bring your own variables into line with the standards used in the OpenEdge development tools and their support code.
You should begin a variable with a lowercase letter (or sometimes two) to indicate the data type of the variable. This can help readers of your code to understand at a glance how a variable is being used. When you start doing more dynamic programming later on, it is very important to differentiate between a variable that represents a value directly, and one that is a handle to an object that has a value. Here are some recommended data type prefixes:
The rest of the name should be in mixed case, where capital letters are used to identify different words or subparts of a name, as in cCustName or iOrderCount.
Placement of variable definitions
Where you place variables in your code also makes a difference. Progress does a single pass through the statements in a procedure to build the intermediary code that it uses to execute the procedure. Because a variable is a definitional element of a procedure and not a statement that is executed in sequence, it does not really matter where the variable definition appears. However, because of the one-pass nature of the Progress syntax analyzer, the definition has to appear before the variable is used in the procedure. By convention, it is usually best for you to define all your variables at the top of a procedure, to aid in readability and to make sure that they’re all defined before they’re used.
For the next change to the test procedure, you will put to work several of the concepts you’ve just learned about. You will display a special value for each Order record. This task involves defining a variable with an initial value, writing an
IF-THENconstruct with a check for the Unknown value, and then using one of the many built-in Progress 4GL functions to extract a value to display. The value you will display is the ShipDate month of an Order expressed as a three-character abbreviation, such as JAN or FEB.To build up the list of possible values for the month, you need to define a
CHARACTERvariable to hold the list. Add the following variable definition to the top of your procedure:
DEFINE VARIABLE cMonthList AS CHARACTER NO-UNDOINIT "JAN,FEB,MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,NOV,DEC".
Defining an IF-THEN-ELSE decision point
You’ll notice when you run your procedure that some of the ship dates aren’t defined. Some of these Orders apparently have been on hold for a very long time! Let’s construct a statement to branch in the code depending on whether the ShipDate field is defined or not. The 4GL, like most languages, has an
IF-THENconstruct for such decision points. It can also have anELSEbranch:
The
conditionis any expression that evaluates to true or false. Following theTHENkeyword, you can place a single 4GL statement, or a whole set of statements that are all to be executed if the condition is true. The way to represent a block that simply groups a series of statements together that are all executed together is aDO-ENDblock:
If you include the
ELSEkeyword followed by a statement or a block of statements, that branch is taken if theconditionevaluates to false.Using the Progress Unknown value
Although the ShipDate is displayed as being blank in these cases, the value stored in the database isn’t a blank value, because this is a date, not a character value. If you were to add an expression to your code to compare the ShipDate to a blank value, you would get your very first Progress 4GL compiler error:
Whenever you press the F2 key to run your procedure, Progress performs a syntax validation. If it can’t properly process the code you’ve written, you get an error such as this one. In this case, Progress sees that you’re trying to compare a field defined to be a date with a character string constant, and these don’t match. To correct this, you need to change the nature of your comparison.
The value stored in the database to represent a value that isn’t defined is called the Unknown value. In 4GL statements you represent the Unknown value with a question mark (?). Note that you don’t put quotation marks around the question mark; it acts as a special symbol on its own. It is not equal to any defined value. In the 4GL, you write a statement that looks as though you are comparing a value to a question mark, such as
IF ShipDate = ?,but in fact the statement is asking if the ShipDate has the Unknown value, which means it has no particular value at all. The Unknown value is like theNULLvalue in SQL, and the expressionIF ShipDate = ?is like the SQL expressionIF ShipDate IS NULL.Using built-In 4GL functions
To complete this latest change to the procedure, you need to define the statement that checks whether the ShipDate is Unknown, and then picks out the month from the date, using the cMonthList variable you defined just above, and converts it to one of the three-letter abbreviations in the list. Here is the whole statement:
Now take a closer look at the elements in the
DISPLAYstatement. First there is a new keyword,ENTRY. This is the name of a built-in function in the 4GL. There are many such functions to do useful jobs for you, to save you the work of writing the code to do it yourself. TheENTRYfunction takes two arguments, and as you can see, those arguments are enclosed in parentheses. The first is anINTEGERvalue, which identifies an entry in a comma-separated list of character values. In this case it represents the month of the year, from 1 to 12. The second argument is the list that contains the entry the function is retrieving. In this case it is the variable you just defined.Looking closer, you can see that the first of the two arguments to the function,
MONTH(ShipDate),is itself another function. This function takes a ProgressDATEvalue as an argument, extracts the month number of the date, and returns it. The returned value is anINTEGERfrom 1 to 12 that theENTRYfunction then uses to pick out the right entry from the list of months in cMonthList. So if the month is May, theMONTHfunction returns 5 and theENTRYfunction picks out the fifth entry from the list of months and returns it to theDISPLAYstatement.Here are some general observations about built-in functions:
- A function takes a variable number of arguments, depending on what the function requires. Some functions take no arguments at all (for example, the
TODAYfunction, which returns today’s date). Some functions have a variable number of arguments, so that one or more arguments at the end of the argument list are optional. For example, theENTRYfunction can have an optional third argument, which is a character string representing a delimiter to use between the values in the list, if you don’t want it to use a comma (,). Because the comma is the default delimiter, it is optional. You can’t leave out arguments from the middle of the list, or specify them in a different order. Each of the arguments must be of the proper data type, depending on what the function expects.- The arguments to a function can be constant values, variable names, database field names, or any expression involving these which evaluates to a value of the proper data type.
- Each function returns a value of a specific data type.
- You can nest functions to any depth in your code. The result of any function is returned up to the next level in the code.
- You can place functions anywhere within a statement where a value can appear. Because a function returns a value, it can appear only on the right-handside of an assignment statement. You can’t use the
MONTHfunction to assign the month value to a date variable, for example, or theENTRYfunction to assign the value of an entry in a list. There are 4GL statement keywords in some cases to do those kinds of assignments.- If you are displaying the result of a function or an expression involving a function, you can specify a
LABELorFORMATfor it, just as you can for a variable. The defaultLABELfor an expression is a text string representing the expression itself. The default format is the default for the function’s data type. In this example you should add the label Month to the expression.To display the month along with each Order:
- Add the new statement with the function references into your procedure, inside the block of code that loops through the Orders:
- To see the effect of the new code, rerun the procedure:
Note: Several separate 4GLDISPLAYstatements contribute to the display of fields in a single line for each Order. This is one of the powerful and flexible characteristics of the 4GL. Progress can gather together a number of different statements in a procedure, some of which might be executed conditionally, and combine them together into a single operation such as this. This feature is generally not possible with other programming languages.- To save your procedure, press F6.
Progress 4GL Functions
This section provides a quick summary of some of the most useful functions available to you in the 4GL:
Other sections of the book look at functions that convert data values and otherwise operate as part of data retrieval.
Date functions
Table 2–5 describes functions that return or operate on data values.
Functions that convert data are discussed in later chapters. An example of one for now is the
STRINGfunction.To see how you can use the
STRINGfunction to convert the time into a meaningful display:List functions
The functions described in Table 2–6 operate on lists. All the list functions are one-based, that is, the first element in a list is considered to be element 1, not 0.
4GL string manipulation functions
The functions described in Table 2–7 operate on character strings.
Putting a calculation into your procedure
The next change to your sample procedure is to perform a simple calculation and display a value based on the result. This section provides an introduction to representing arithmetic expressions in the Progress 4GL. It also discusses how to use some of the special built-in functions for advanced arithmetic operations.
Arithmetic expressions and operands
The Progress 4GL supports the set of arithmetic operands described in Table 2–8. You can use these operands to define expressions. You might be familiar with them from other programming languages you have used.
There’s one special thing you need to know when you’re writing expressions involving these operands. Because the Progress 4GL allows the use of a hyphen as a character in a procedure name, variable name, or database field name, it cannot recognize the difference between a hyphen and a minus sign used for subtraction, which are the same keyboard character. For example, there’s no way for the syntax analyzer to tell whether the string
ABC-DEFrepresents a single hyphenated variable or field name, or whether it represent the arithmetic expressionABCminusDEF, involving two fields or variables namedABDandDEF. For this reason, you have to put a space or other white space characters around the “-” character when you use it as a minus sign for subtraction of one number from another. Note that you don’t have to insert a space after a minus sign that precedes a negative number, such as–25. For consistency, the other arithmetic operands also require white space. If you forget to put it in, you’ll get an error, except in the case of the forward slash character. In the case of the slash, if you leave out the white space, Progress interprets the value as a date! So, for example,5/6represents May 6th, not a numeric fraction.To illustrate how to use arithmetic operands in the sample procedure, you need to determine whether the CreditLimit of the Customer is less than twice the outstanding Balance. If this is true, then you must display the ratio of CreditLimit to Balance. Otherwise you display the Orders for the Customer. Add the following code, just in front of the
FOR EACH Order OF Customerstatement that’s already there:
IF CreditLimit < 2 * Balance THENDISPLAY "Credit Ratio:" CreditLimit / Balance.ELSEFOR EACH Order OF Customer:
You can add parentheses to such an expression to make the grouping of terms explicit. Otherwise, Progress observes the standard rules of precedence. Multiplication and division are performed before addition and subtraction, and all such calculations are performed before a comparison operation.
The expression following the
IFkeyword compares the CreditLimit field from the current Customer record with two times the value of the Balance field. If the first value is less than the second, then the expression is true and the statement following theTHENkeyword is executed, which displays the string expression Credit Ratio: followed by the value of the CreditLimit divided by the Balance.The
ELSEkeyword is followed by the entireFOR EACH Orderblock, so that block of code, which displays all the Orders of the Customer, is skipped if the expression is true, and executed only if it is false.To see the result of this change, run your procedure again. For a Customer where the ratio is greater than or equal to 2, the Orders display as before. For a Customer where the ratio is less than 2, the new expression is displayed instead:
![]()
You might notice a couple of things about this display:
- Because the CreditLimit check is in the block of code where the procedure retrieves and displays Customers, it is displayed in the same frame as the Customer information. You can give names to frames to be more specific about the frame in which to display objects, as well as where in the frame each element is displayed. You’ll learn more about naming frames in "Introducing the OpenEdge AppBuilder."
- Progress understands enough about what is going on here to clear and hide the Order frame if it’s not being displayed for the current Customer (because the CreditLimit to Balance ratio is being displayed instead). This is part of the very powerful default behavior of the language.
Arithmetic built-in functions
Table 2–9 describes some of the useful built-in functions that extend the basic set of numeric operands.
Using the Intelligent Edit Control and its shortcuts
The first step in the next part of your sample procedure involves defining another program variable. You won’t do too many of these before you might begin to get tired of typing the words
DEFINE VARIABLEandNO-UNDOand so forth over and over again. In fact, you don’t have to do all that typing at all.You’ve already seen that when you use the Progress Procedure Editor to edit your Progress 4GL code, you are using an intelligent syntax editor that can perform many tasks for you. One of these is syntax completion. Using this feature can save you many keystrokes in your programming, helps to prevent typographical errors, and helps to impose a standard form to your code.
To define a new
INTEGERvariable for your procedure:
- Position the cursor to the beginning of the line where you want the definition to go, following the variable definition you have already, then enter the letters DVI, or DVIN, which stand for Define Variable INteger.
- Press the SPACE BAR. The following code appears:
The textDEFINE VARIABLE AS INTEGER NO-UNDOis inserted for you, and the cursor is placed right where you need it so you can enter the variable name.- Type iDays as the variable name. You’ll use this variable later.
Here are the abbreviations for other data types that you’ve learned:
To see all the abbreviations (also called aliases) and other editing options available to you, select Options
Editing Options from the Procedure Editor menu. The Editing Options dialog box appears:
![]()
Among other things, this dialog box specifies the following default settings:
- The syntax expansion that turns DVI into
DEFINE VARIABLE AS INTEGER NO-UNDOis turned on (the Syntax expansion toggle box).- Lines of your program are indented based on the Editor’s understanding of the statements you’re entering (the Indent style selection).
- Tabs are set to 4-character intervals (the Tabs fill-in field).
To see a list of all the aliases (also called shortcuts) that are defined, choose the Alias button. The Alias Editor dialog box appears:
![]()
In this dialog box you see all the aliases for the
DEFINE VARIABLEstatement, along with a number of other useful ones, including one that automatically respells the (apparently) common typographical errorDIPSLAYasDISPLAY. Aliases can be further abbreviated to any unique substring of the alias, which is why DVI works as well as DVIN. Note that you can also define new aliases of your own. They are stored in a file calledp4gl.als.To peruse another set of options that you can customize, choose OK to return to the main Editing Options dialog box, then choose the Options button. The Progress 4GL Options dialog box appears:
![]()
This dialog box includes, among other options, the automatic uppercasing of keywords that you’ve seen in action. If this isn’t your preference, you can turn it off.
To customize which keywords you want colored and what colors to use, choose OK to return to the Editing Options dialog box, then choose the Color Coding button. The Color Coding Setup dialog box appears:
![]()
If you choose the Help button on any of these dialog boxes, you can see detailed information on all the options available to you.
Getting to online help
You can access the OpenEdge Online Help system at any time just by pressing the F1 key. Help is context-sensitive, so it always tries to come up initialized to a section of the help files that seems relevant to what you’re doing. For example, if you press F1 from within the Editing Options dialog box, you get help on the options in that dialog box:
![]()
In a Progress editor, if you highlight one or more keywords in a procedure and press F1, you get help for that type of statement.
To try accessing online help:
- In your test procedure, highlight the keywords
DEFINE VARIABLE, then press F1:
The online help window appears showing the help keyword index:
![]()
- Choose Display to see the help text for this entry:
![]()
- Choose the Contents button to access the available online help for all the OpenEdge tools, or choose the Find button to specify one or more key words to search for in the help text.
Saving and compiling your test procedure
You’ve written your first Progress 4GL procedure. As you make changes to it, you should resave it by selecting File
Save from the Procedure Editor menu or by just pressing F6.
This section examines what happens when you press the F2 key or select Compile
Run from the menu to run your procedure:
- When you tell Progress to run your procedure in this way, the Procedure Editor creates a temporary file from the 4GL code currently in the editor window and then passes this file to the Progress compiler.
- The compiler performs a syntax analysis of the procedure and stops with one or more error messages if it detects any errors in your 4GL statements.
- If your procedure is error-free, the compiler then translates or compiles your procedure into an intermediate form that is then interpreted by the Progress run-time interpreter to execute the statements in the procedure. This intermediate form is called r-code, for run-time code. It is not a binary executable but rather a largely platform-independent set of instructions (independent except for the user interface specifics, that is).
- The Progress run-time interpreter reads and executes the r-code.
This ability to compile and run what’s in the editor on the fly makes it easy for you to build and test procedures in an iterative way, making a change as you have done and then simply running the procedure to see the effects. Naturally, you want to save the r-code permanently when you have finished a procedure so that Progress can skip the compilation step when you run the procedure and simply execute the r-code directly. Generally it is just the compiled r-code that you deploy as your finished application.
To save the source procedure itself, use the standard File
Save As menu option in the Procedure Editor, which saves the contents of the editor out to disk and gives it a filename with a
.pextension.To compile a procedure that you have saved, you need to use the
COMPILEstatement in the 4GL. There’s aCOMPILEstatement rather than just having a single key to press because theCOMPILEstatement in fact has a lot of options to it, including where the compiled code is saved, whether a cross-reference file is generated to help you debug your application, and so forth. For now, it is sufficient to know just the simple form of the statement you use to save your compiled procedure.To compile your test procedure:
- From the Procedure Editor, select File
New Procedure Window.
Another editor window appears that has all the same capabilities as the one with which you started out, except that not all the menu options are available from it. You can be working with any number of procedure windows at one time, and save them independently as separate named procedures. Or you can bring up a window just to execute a statement, as you are doing now.- In the new editor window, enter the following statement:
- Press F2 or select Compile
Run. The procedure window disappears and almost immediately returns.
The compilation of
h-CustSample.pis complete. If the compiler had detected any syntax errors in the procedure, you would have seen them and the procedure would not have compiled.If you check your working directory you can see the compiled procedure. It has the
.rextension and is commonly referred to as a .r file.One option for the
COMPILEstatement is worth mentioning at this time. You can specify a different directory for your.rfiles. This is a good idea, especially when you get to the point where you are ready to start testing completed parts of your application. Use this syntax:
If you need to recompile a large number of procedures at once, you can use a special tool to do that for you. This is available through the Tools
Application Compiler option on the Procedure Editor.
Now you’ve compiled your first procedure! In the next chapter, you learn how to run one procedure from another.
|
Copyright © 2005 Progress Software Corporation www.progress.com Voice: (781) 280-4000 Fax: (781) 280-4095 |
![]() ![]() ![]()
|