=================================
                                RELEASE NOTES
                                     FOR
                      INFORMIX 6.00.UE1 PRODUCT RELEASE
                               DATE: 05/13/94
                      =================================

TABLE OF CONTENTS
I.     OVERVIEW OF RELEASE NOTES
II.    PRODUCTS CONTAINED IN THE 6.00 TOOLS RELEASE
III.   SPECIAL CONSIDERATIONS FOR DEVELOPERS USING 6.00 RELEASE SOFTWARE 
    A. Information for Everyone -- Special Topics for this Release
    B. Selected Notes from Earlier Releases
IV.  BUGS FIXED IN THIS RELEASE
V.   KNOWN PRODUCT DEFICIENCIES

I. OVERVIEW OF RELEASE NOTES The purpose of these release notes is to inform the user of changes in products that might affect existing applications. The release notes contain information on changes from previous releases, known problems, and work-arounds. Bug identification numbers are assigned to known problems to assist you in identifying the problems to Technical Support. This document is not all-inclusive but is a tool to assist you in the update process. Please consult Informix product manuals for additional information on product features and for clarification of product behavior. The 6.00 Tools release is basically a 4.12 release that can work with the 6.00 engines directly (avoiding the overhead of using the Relay Module) and with NLS functionality added. However, the 6.00 tools will not work with any engines earlier than the 6.00 engines. The two releases have occurred at approximately the same time. We expect that customers who need to work with 6.00 engines, or who need NLS functionality, will probably skip right over the 4.12 release altogether. For this reason, the 4.12 release notes have been combined with the 6.0 release notes for the 6.0 release. Customers who have both releases will see the duplications in the release notes.
II. PRODUCTS CONTAINED IN THE 6.00 TOOLS RELEASE The following products are contained in the 6.00 tools release: Product Name ------------ INFORMIX-4GL INFORMIX-4GL Runtime Facility INFORMIX-4GL/Rapid Development System INFORMIX-4GL/Rapid Development System Runtime Facility INFORMIX-4GL/Interactive Debugger INFORMIX-SQL INFORMIX-SQL Runtime Facility
III. SPECIAL CONSIDERATIONS FOR DEVELOPERS USING 6.00 RELEASE SOFTWARE NOTATION -------- I4GL refers to (compiled) Informix-4GL. RDS refers to the Informix-4GL Rapid Development System. ID refers to the Informix-4GL Interactive Debugger. 4GL refers to any of the Informix-4GL products. ISQL refers to Informix-SQL. ESQL/C refers to Informix-ESQL/C. I4GLC1 6.00 I4GL Phase 1 compiler I4GLC2 6.00 I4GL Phase 2 compiler I4GLC3 6.00 I4GL Phase 3 compiler I4GLC4 6.00 I4GL Phase 4 compiler FGLC 6.00 I4GL Shell script for Phases 1 and 2. FGLC2 6.00 I4GL Shell script for Phases 3 and 4. fglc 4.xx I4GL Phase 1 compiler fglc2 4.xx I4GL Phase 2 compiler fglc3 4.12 I4GL Phase 3 compiler I4GL/PE I4GL Programmer's Environment R4GL/PE RDS Programmer's Environment C4GL I4GL Shell script that invokes the compilers. INSTALLATION ------------ It is recommended that the 6.00 Tools are installed in a new directory, along with the 6.00 Engines, rather than being installed on top of previous versions of Informix products. Many files have been relocated or renamed. It will be much easier to remove redundant files if the old $INFORMIXDIR directory can be removed completely (after testing the new installation, of course) than if you have to spend time removing old files manually. A. Information for Everyone -- Special Topics for this Release COMPATIBILITY ============= The two main reasons for the introduction of 6.x tools are 1) to avoid the overhead of the Relay Module that dynamically translates older applications to use the 6.x engines properly, and 2) to use new NLS functionality. The 6.x database engines are a *major* product upgrade from the 4.x versions; as an unfortunate but inevitable result, most applications developed using 4.x (or earlier) INFORMIX tools will have to be recompiled. This is because ESQL/C, our 6.x tools interface to the backend, now makes a distinction between prepared cursors (now called "statements") and declared cursors. In 4.x and earlier versions of ESQL/C, an examination of the C code generated from ESQL/C would show that the generated code would use the same static cursor for both prepared cursors (cursors defined with "prepare") and "declared" cursors (cursors defined with "declare"). All information for both kinds of uses would be contained within the same structure. However, 6.x engines functionality has been improved so that, for example, multiple declared cursors can be associated with the same prepared statement. Additionally, there is new functionality called "dynamic cursors", that allows the user to create cursors as needed with dynamically created names and features; this functionality simply cannot be supported by ESQL/C's old method of statically allocating cursors. For the vast majority of ESQL/C users, this upgrade will be transparent, but for certain applications with specialized knowledge, such as the RDS interpreter, the distinction is important, and creates compatibility constraints (see below). THE RELAY MODULE ---------------- 4.x applications can be run against 6.0 engines without being recompiled using the new Relay Module. You would need to set the SQLEXEC environment variable to SQLRM. (See the sections on the environment variables SQLEXEC and SQLRM in "Informix Guide to SQL: Reference, Version 6.0.") C Shell: setenv SQLEXEC sqlrm Bourne or Korn Shell: SQLEXEC=sqlrm; export SQLEXEC However, you will get better performance when accessing the database if your 4GL programs and linked ESQL/C modules are recompiled using the 6.0 tools. (There is no need to recompile linked in c modules that were not generated from INFORMIX preprocessors.) Note that any attempt to mix modules compiled with 4.xx tools with modules compiled with 6.x tools will result in undefined behavior. The program may fail to link, but it will more probably link and run and then fail in mysterious ways. You must either recompile all the modules in a program using the 6.x tools, or do not recompile any of them and use the Relay Module to access the 6.x engine. I4GL ---- You must recompile all your I4GL source code, and any related ESQL/C code, to avoid using the Relay Module and to gain access to the NLS functionality. You do not have to recompile form files or message files. Do not try mixing code compiled with any earlier version of I4GL with code compiled with version 6.0 of I4GL. You can recompile using either the C4GL script or the I4GL/PE program. RDS & ID -------- You should recompile all your RDS source code to avoid using the Relay Module and to gain access to the NLS functionality. You do not have to recompile form files or message files. You can recompile using either the FGLPC program or the R4GL/PE program. The output of 6.x fglpc is level 10 pcode, and cannot be run by any fglgo runner, customized runner or ID runner earlier than 6.0; nor can any 6.x fglgo runner, customized runner, or ID runner run modules compiled with an fglpc of a version earlier than 6.0. Attempts to do so will get error messages specifying that you are running the wrong level of pcode. If you use custom runners, you will need to recompile them to avoid using the Relay Module. If your runner is built with any ESQL/C modules, you should recompile the ESQL/C code as well as relinking the runner, using the 6.x cfglgo and cfgldb scripts. ISQL ---- If you use customized ACE or PERFORM runners, you will need to recompile them to avoid using the Relay Module and to gain access to the NLS functionality. It is not necessary to recompile the reports or forms themselves. USING MAKE ---------- You will find that all the libraries and headers have been moved under $INFORMIXDIR, and that the list of libraries has changed. If you use MAKE or an equivalent program and you list the Informix headers or libraries which are linked into any executable (whether it is a custom runner or an I4GL program), then you will have to update your makefile. Alternatively, do not list the Informix libraries or headers in the makefile as the file list may change with any release of Informix products. UPSCOL, DEMOS, ETC. ------------------- You should not need to change any features of the UPSCOL or DEMOS to work with 6.x tools. However, if you have INFORMIX DEMOS that were compiled under 4.x, you will need to use the Relay Module. Recompile these under the 6.x environment to use the faster direct access functionality. DATABASES --------- Your old databases will automatically be updated when you first use them with the new 6.x engine. See the manuals and release notes for the engine products for more information about this. EMBEDDED LANGUAGES ------------------ ESQL/Ada and ESQL/Fortran have not been upgraded to 6.x level, so it will not be possible to run 6.x 4GL programs linked with ESQL/Ada or ESQL/Fortran modules. You will have to run these modules linked with 4.x 4GL programs through the Relay Module. There are 6.x versions of ESQL/Cobol and ESQL/C. If you recompile 4GL programs to take advantage of the functionality and speed of the 6.x tools, you must recompile these linked modules as well. LOCALE INFORMATION ================== Software for non-English languages requires special handling in order to behave correctly for a non-English user. All of the basic notions of a language must be built into the product if the software is to appear to work correctly for a non-English language. Essential notions like sorting order, capitalization, and numeric display format do not come for free. Each extra language that you wish to support must come equipped with its own code-set (i.e. the set of all valid characters for that language), and its own collation tables (i.e. the "dictionary" order). Extra code must be added to the tools in order to read and interpret this information. The 4.12 release of tools does not come equipped with support for German, French, etc. in the sense mentioned above. The 4.12 release (and all previous releases) are equipped with the ability to store and display any of the 256 possible characters that one byte can hold (except '\0'). Version 4.12 endows these characters with purely English semantics. Notions of capitalization, sorting, and numeric format are all oriented towards standard U.S. expectations. Since the code was not originally designed to handle characters like á, è, ö, þ, ø, and ð; it will not be able to properly capitalize them, nor will it be able to properly compare strings that use these characters. In fact, any behavior that involves the expected semantics of characters which are not in the English alphabet is not guaranteed to work. There are a limited number of exceptions to this broad rule. Since 4.12 is 8-bit clean, we can expect that this tool set will be able to handle simple storage and display of data employing non-U.S. characters (assuming that the display device itself is capable of displaying the relevant characters). One more exception to the above mentioned rule is that 4.12 implements the "identity semantics" of all characters. This means that two strings which look identical are compared identically (i.e. the string "ðéþ" and "ðéþ" compare for equality as "True"). If two strings are identical except for case (relative to some particular language) there is simply no way for pre-6.00 tools to recognize any similarity. If two strings do not look identical but in some language they are supposed to be identical, no pre-6.00 tool will be able to tell the difference. Locales ------- Be aware that some of the locales supplied by some platforms are incorrect. Bad locale files result in symptoms ranging from minor formatting errors (e.g. incorrect decimal separators) to data corruption in columns of type CHAR and VARCHAR. Also be aware that the "C" locale (provided as a default on many systems) is not a valid locale for most uses of Informix products. The "C" locale gives no information concerning numeric or currency format. Use of the "C" locale can cause 4GL to complain about input errors even when the input has been typed correctly. If you want to use the standard U.S. format that 4GL and ISQL employ, do one of the two following things: 1) set DBNLS to zero (thus turning off NLS functionality), or 2) obtain a locale for the U.S. and set LANG to refer to this locale (e.g. setenv LANG En_US). Note that many systems come configured with the C locale as the default. Another potential danger relating to locales is found in heterogeneous client/server environments. If the client and server are ostensibly running with the same language but with slightly different collation orders, counter-intuitive results may appear. This situation is possible if the locale files that represent the language are different on the client and server sides. STTY settings ------------- In order to use NLS characters, you will need to set your display device to allow the entry of 8-bit characters with the stty command (typically using "stty cs8"). If you are using the terminal emulator on a workstation as your display device, make sure it can display international characters correctly. For example, the default font for some versions of xterm does not display legible glyphs for non-ASCII characters. CHANGES TO THE COMPILATION SYSTEM ================================= There are some significant differences in the way that Version 6.00 of I4GL compiles 4GL source code compared with all previous versions. Here is a summary of the changes; the details follow in the numbered sections: ------------------------------------------------------------------ 1. The 5-phase I4GL compilation process. 2. FGLC and FGLC2 shell scripts for backward compatibility. 3. I4GL/PE always uses the C4GL script to do compilations. 4. C4GL uses the new "-phase" option. 5. C4GL uses the new "-keep" and "-nokeep" options. 6. C4GL uses the new "-z" option. 7. C4GL uses the new "-globcurs" option. 8. C4GL uses the INFORMIXC and CC environment variables. 9. C4GL uses the C4GLFLAGS environment variable. 10. The I4GL libraries and header files have been moved. 11. Future Changes. 12. I4GLC4. ------------------------------------------------------------------- 1. The 5-phase I4GL compilation process. To make I4GL independent of ESQL/C, an extra process has to be introduced into the compilation sequence compared with the Version 4.12 compilation process (or two extra steps compared with versions earlier than 4.12). The five compilation phases in the Version 6.00 compilation are shown diagrammatically on the next page, and they are compared with the equivalent steps for the version 4.12 compilation, and for the 4.11 or earlier compilation. The five phases are: I4GLC1: converts a 4GL source file with ".4gl" extension into a file with ".4ec" extension. It parses the 4GL language and generates C code to handle function and report definitions, computations, and function calls. It generates extended ESQL/C statements to handle forms, menus, input statements, and display statements, and pure ESQL/C to handle SQL statements and variable declarations. I4GLC1 is the same as 4.xx fglc, except for the fact that I4GLC1 generates a ".4ec" file instead of a ".ec" file. I4GLC2: is a simplified version of 4.xx fglc2. Where fglc2 translated both the extended ESQL/C statements and pure ESQL/C statements into pure C, I4GLC2 only translates the extended form, menu, input, and display statements to pure C code, but leaves variable declarations and SQL statements unchanged. I4GLC2 accepts a ".4ec" file generated by I4GLC1 as input and produces a ".ec" file containing pure ESQL/C. I4GLC3: is a copy of the standard 6.00 ESQL/C compiler. I4GLC3 accepts a ".ec" file (which may have been produced by I4GLC2 or written as pure ESQL/C), and produces a ".c" file. The declarations and the SQL statements are mapped to pure C. Version 6.00: Version 4.12: Version 4.11 or earlier: file.4gl file.4gl file.4gl | | | v v v +--------+ +--------+ +--------+ | I4GLC1 | | fglc | | fglc | +--------+ +--------+ +--------+ | | | v v v file.4ec file.ec file.ec | | | v v v +--------+ +-------+ +-------+ | I4GLC2 | | fglc2 | | fglc2 | +--------+ +-------+ +-------+ | | | v | | file.ec | | | | | v | | +--------+ | | | I4GLC3 | | | +--------+ | | | | | v | | file.c file.c | | | | v v | +--------+ +-------+ | | I4GLC4 | | fglc3 | | +--------+ +-------+ | | | | v v v file.c file.c file.c | | | v v v +-------+ +-------+ +-------+ | CC | | CC | | CC | +-------+ +-------+ +-------+ | | | v v v file.o file.o file.o or or or file.4ge file.4ge file.4ge I4GLC4: is the same as the 4.12 program fglc3. It converts C code which may contain international characters in variable names into de-internationalized names. This step is necessary to ensure that defining a record like table.* or a field like table.column will not produce C code which contains international characters as very few C compilers will accept these characters in variable names. C Compiler: Informix uses the system C compiler to convert the C code generated by I4GLC3 or I4GLC4 into object files and executable programs. 2. FGLC and FGLC2 shell scripts for backward compatibility. The FGLC and FGLC2 shell scripts are provided for backwards compatibility. Since the compilers fglc and fglc2 reside in $INFORMIXDIR/lib in 4.xx, the new shell scripts will take their place in the same directory in the 6.00 I4GL product. As fglc converted a ".4gl" file into a ".ec" file, it corresponds to the job done by I4GLC1 and I4GLC2. The ".ec" file generated by FGLC is different from the one generated by fglc because the output of FGLC is a pure ESQL/C program, whereas the output from fglc contained extended ESQL/C statements such as $MENU, $DISPLAY, and $INPUT, but these only appear in .4ec files now. Similarly, fglc2 converted an (extended) ESQL/C file into a pure C file, so it corresponded to the job done by I4GLC3 and I4GLC4. The difference is that the ".ec" file in 4.xx contained a mixture of forms statements and ESQL/C statements, whereas in 6.00 the ".ec" file will be pure ESQL/C. The script FGLC2 executes C4GL with the argument "-phase 34" to perform the steps I4GLC3 and I4GLC4 for producing a ".c" file. 3. I4GL/PE always uses the C4GL script to do compilations. Prior to 4.12, I4GL/PE used built-in knowledge about what commands need to be executed to convert a ".4gl" file into a ".ec" file, and a ".ec" file into a ".c" file, and a ".c" into a ".o" file or executable file. This has included details such as the list of library names and special options. With the advent of Version 6.00 Engines, the 6.00 version of I4GL has to take into account that the database, table and column names could contain international characters. These will not be accepted in variable names by most C compilers, so the I4GLC4 process maps the international characters so that they will be accepted by C compilers. This meant that I4GL/PE had to be changed. To simplify the changes required, and to simplify the code stream so that there is no difference between the 6.00 and 4.12 I4GL/PE programs, the compilation scheme was revised so that I4GL/PE invokes C4GL to do the compilation, using the "-phase" option described below. I4GL/PE now runs "c4gl -phase 12" (I4GLC1 and I4GLC2) as its own phase 1, followed by "c4gl -phase 34" (I4GLC3 and I4GLC4) as its own phase 2, and finally it runs "c4gl -phase 5" (the C compiler) as its own phase 3. There has never been a facility to allow the user to specify array bounds checking (using the "-a" flag) for compilations done by way of I4GL/PE. However, because the C4GL script is used for the compilations, the C4GLFLAGS environment variable (see below) can be used with I4GL/PE too. 4. C4GL uses the new "-phase" option. C4GL needed some new options to support the new behavior of I4GL, but, in general, the old behavior has been retained as the default. C4GL now recognizes the 5 phases of compilation outlined above. There is a new option "-phase" that takes an argument separated from "-phase" by one or more spaces. This argument can contain any contiguous sequence of numbers between 1 and 5 (that is, 1, 2, 3, 4, 5, 12, 23, 34, 45, 123, 234, 345, 1234, 2345, 12345), with the default being 12345. The older "-e" option has been retained and corresponds to "-phase 1234". The old "-c" option implies "-phase 12345" , but the C compiler will only generate the object files and not link them to produce an executable. 5. C4GL uses the new "-keep" and "-nokeep" options. C4GL, by default, removes the intermediate files that it generates when the compilation is successful. This is a change from 4.12 and earlier versions. Thus, the ".c", the ".ec", and the ".4ec" files that are generated are removed when the compilation completes successfully. If the compilation fails for any reason, or is interrupted, then all the intermediate files are left intact. The new "-keep" option explicitly specifies that the intermediate files are to be retained. The "-nokeep" option specifies that the intermediate files are to be removed, and is the 6.00 default. The ".o" file will be retained if the "-c" flag is specified. However, if an executable is produced, the ".o" file will be kept or removed depending on the C compiler in use. Some will retain the ".o" file; others will remove it; and the behavior may depend on what other files are specified on the command line. Note that if the script is commanded to do "-phase 1234", the ".c" file is no longer an intermediate file and is retained. Similarly, if phase 1 is requested, the ".4ec" is no longer an intermediate file and is retained. Unless compilation is successful, no intermediates are removed. 6. C4GL uses the new "-z" option. C4GL recognizes the "-z" option which allows a single function to be invoked with a variable number of arguments without I4GLC1 complaining at compile time. Although the "-z" option was supported by 4.xx versions of fglc, the C4GL shell script ignored the option so it was not possible to use the standard script to compile programs with such functions. Note that it is dangerous to use this option as it suppresses all error messages for all functions with variable numbers of arguments; there are generally very few (if any) of these functions in a program. 7. C4GL uses the new "-globcurs" option. In 4.xx I4GL and ESQL/C, all cursor and statement names were local to a single file, and reusing the same name in different files did not lead to any problems. In 5.0x and 6.x ESQL/C, all cursor and statement names are global by default. This means that the cursor c_query in filea.ec is the same as the cursor c_query in fileb.ec. To preserve the old behavior (in both I4GL and RDS), all cursor and statement names are mangled by the compiler, using the same algorithm in both compilers. The mangled name is always 18 characters long. The first half is derived from the inode number of the 4GL source file, and the second half is derived from the user-supplied name, using the algorithm shown below. It is possible that two distinct names in the same file may end up with the same mangled name, which could lead to a variety of problems. The algorithm is documented so that if you run into problems, you can at least find out what the trouble is. Please let Informix know of any pairs of cursor or statment names that are mangled to the same value. The workaround is to change one of the cursor or statement names. The new option "-globcurs" is provided to allow the programmer to make the cursors global to the entire program. Note that the compilers still insists that the cursor is declared in the module before it is used for any other purpose in the module, so this option will seldom be useful. However, it may help in debugging as the cursor names are not modified. Note: "-globcurs" can also be used with FGLPC. The hashing scheme used by I4GL is identical to the one used by RDS. The code snippet which hashes a cursor name is shown below: ... sprintf(mangled_name, "I%08X_%08X", inode_number, hash_cursorname(cursor_name)); ... static unsigned long hash_cursorname(name) char *name; { unsigned long uhash = 0x14C1BC85; unsigned long g; unsigned char *s; unsigned char c; for (s = (unsigned char *)name; (c = *s) != '\0'; s++) { uhash = (uhash << 4) + (c); if ((g = uhash & 0xF0000000L) != 0) { uhash = uhash ^ (g >> 24); uhash = uhash ^ g; } } return(uhash); } Note that the cursor name mangling scheme makes it difficult for an ESQL/C module to use cursors or statements from an I4GL module. Since it was impossible to share the cursors in 4.xx, there is no existing code which is affected. Also note that Version 6.00 4GL still works in terms of 4.xx rules, so cursors cannot be created in one 4GL module and referenced in another. 8. C4GL uses the INFORMIXC and CC environment variables. C4GL uses the INFORMIXC and CC environment variables (defaulting to "cc" on most machines) to do the final stage of compilation. This allows users to substitute any C compiler as desired by setting one of these environment variables. Note that CC is acknowledged by many versions of MAKE as well, so this environment variable is compatible with other programs, as well. The Bourne shell code used to determine the compiler used is equivalent to: ${INFORMIXC:=${CC:-cc}} This means that if there is an INFORMIXC environment variable which is not empty, use the value of that for the compiler; if not, use the (non-empty) value of the CC environment variable; if neither of those exist, default to cc. Note for users of GCC: Informix assumes that strings are writable, so you will need to compile using the "-fwritable-strings" option. Failure to do so will have unpredictable results, possibly including core dumps. 9. C4GL uses the C4GLFLAGS environment variable. C4GL acknowledges the C4GLFLAGS environment variable as extra default options. The flags "-keep", "-a," and "-ansi" can be specified, and all compilations will occur with flags as specified in C4GLFLAGS. Users should not specify "-phase", "-e," or "-c" (or, for the C compiler, "-P", "-E", "-S") in this environment variable as it will prevent the compilations from completing. For example, if you specify "-e" in the C4GLFLAGS environment variable, you will always stop compiling after producing a .c file; you will never produce object or executable files. 10. The I4GL libraries and header files have been moved. The I4GL libraries and header files are located in new directories and are separate from the libraries and header files used by ESQL/C, even though the common files are identical. All the libraries used by 6.00 family of tools are located in $INFORMIXDIR/lib/tools. Similarly, all the header files used by 6.00 tools family are in $INFORMIXDIR/incl/tools. The compilers I4GLC1, I4GLC2, I4GLC3, and I4GLC4 are all located in the $INFORMIXDIR/lib/tools directory, whereas in 4.1x, the corresponding files were located in $INFORMIXDIR/lib. If the programmers explicitly list the headers from the Informix directories in the dependency lines in their makefiles, then the dependency lines need to be modified. Also, if the makefiles explicitly listed the libraries to be linked, then those lists need changing. Not only are the libraries in a different directory, but also both the number and the names of the libraries have changed. On the other hand, if the programmers do not list the I4GL libraries and they simply use C4GL to do the linking, then no change is needed. C4GL has always been portable across the releases. The most reliable way to compile a ".4gl" file to an object file is using "c4gl -c". Similarly, the most reliable way to link a program is using "c4gl -o". 11. Future Changes. The compilation system used in 6.00 may change again in a number of ways in later releases. However, if you only use the C4GL script to produce object (.o) files using the "-c" option, or you use the "-o" option to link programs, then the changes will not affect you. If you use the "-phase" options you may be required to make some small changes in the future. 12. I4GLC4. The information in this section is to help people who use source code debuggers with I4GL programs. The primary conversion done by I4GLC4 is required for to ensure that the generated C code will compile when I4GL is used with an NLS database. In an NLS database, the table and column names can contain non-ASCII characters in the range 128..255. You can define variables using RECORD LIKE Table.* referring to these names, but C compilers don't normally allow such characters to be used in variable names. To avoid compilation problems in the C compiler, the code is adjusted by I4GLC4. To make the variable names safe, we replace any non-ASCII characters that occur outside quoted strings (which will only happen in variable or function names) with a mapped value. For values in the range 0xA0 to 0xFF, we use the hexadecimal value for the character, printed in uppercase hexadecimal. Characters in the range 0x80 to 0x8F are mapped to G0 to GF, and values in the range 0x90 to 0x9F are mapped to H0 to HF. All ordinary I4GL identifier names are converted to lowercase, so there should be no chance of producing a naming conflict. Also, by the time this translation occurs, the names of tables and columns in SQL statements will not be mangled; the names passed to the engine are protected by quotes. I4GLC4 does one other translation, and that only inside strings; it converts y-umlaut (hex 0xFF) into the escape sequence \377. This is because some C compilers are not fully internationalized and read this character as EOF. Note that the P-code compiler, does not do this mapping. Using the ESQL/C compiler for phase 3 introduces yet another complication to the compilation process. Informix-4GL uses a different view of the SQLCA record from ESQL/C -- the warning flags are a series of single characters in ESQL/C but are treated as a string in 4GL code. The ESQL/C compiler automatically includes the header ahead of any user-defined code, which means ahead of the I4GL declaration of the SQLCA record. This would lead to two discrepant definitions of the SQLCA record, and the compilations would fail, unless the C4GL script handled this. To overcome this problem, I4GLC1 emits a line which starts "#define I4GL_SQLCA" just before the declaration of the SQLCA record. This is passed through by I4GLC2 and I4GLC3. If the ".c" file to be processed by I4GLC2 contains this definition, but does not contain the line "#define SQLCA_INCL", then C4GL passes an extra flag to I4GLC4, and it then prepends the line "#define SQLCA_INCL" in front of the C file it translates. This is handled by the C preprocessor so that the contents of the header are ignored, leaving just the I4GL version of the SQLCA record visible to the C compiler. If required, I4GLC4 can be used on its own; it takes the arguments: -V print version information (does not process any files) -D emit '#define SQLCA_INCL' as the first line of output -s ext create backup file with the extension ".ext" -o overwrite input files By default, I4GLC4 writes the mangled file(s) to standard output, but the original file can be overwritten using the "-o" option, or the original file can be backed up with an extension of the user's choosing. There is no default extension. Note that I4GLC4 automatically inserts a "." between the name and the extension. The -o and -s options are mutually exclusive and require a filename argument. Otherwise, I4GLC4 processes any files specified, or standard input if there are no files. CC MUST EXIST ON PATH FOR I4GL ------------------------------ The programmer's environment, I4GL/PE, still checks to see whether it can locate the C compiler cc when you first try to compile something. It does not handle all possible values for the INFORMIXC or CC environment variables, so if you do not have cc on you machine, you may get unnecessary error messages. A simple cure for that is to ensure that there is an executable shell script called cc somewhere on your path. SHARED LIBRARIES ================ Introduction ------------ Effective with the 6.00 release of (compiled) Informix-4GL, a shared library implementation of the 4GL program libraries is provided on many platforms. Use of the shared library provides reduced memory consumption, faster program start-up, and reduced program file sizes (thereby saving file system space). Shared library support is provided for compiled 4GL only. Informix-SQL and Informix-4GL RDS runners (fglgo or custom runners) are inherently shared, since all active users are running the same executable file. This feature will be most useful for those installations which have a variety of compiled 4GL applications: the 4GL library code will exist in only one place in memory and does not have to be added to each 4GL executable file. On a system with a large number of 4GL programs, the disk space and memory savings can be substantial. Unfortunately, Informix cannot provide a shared library implementation on all platforms. On some platforms, shared librararies are simply not available, and on others, the operating system implementation of shared libraries is simply not compatible with the Informix codestream. To determine if your platform has a shared library implementation of Informix-4GL, look at the C4GL help messages. These are displayed when you run "c4gl" with no arguments. There will be a help line for the shared option that contains one of these two messages: -shared Use dynamic linking and shared libraries Or: -shared (Not available on this platform) If the former message is the one given for your platform, then a 4GL Shared Library implementation is provided, and the -shared option is available for your use. You can demonstrate the memory and file size savings for your platform by compiling the Informix-4GL demonstration program ("demo4") with and without the -shared flag, and comparing the outputs of "ls" and "size" for each program: i4gldemo c4gl -shared d4_*.4gl -o demo4.shared c4gl d4_*.o -o demo4 ls -l demo4* size demo4* Some platforms provide commands that shows the dependencies of a compiled program on the shared libraries. For instance, on some Sun platforms, the command to do this is "ldd". For more technical information about shared library concepts, please refer to your operating system documentation. If your system has "man pages" (on-line manuals), the man page for "ld" may direct you to the appropriate area of your system documentation. Usage of the Shared Library Facility ------------------------------------ To compile a 4GL program for shared library execution, simply add the -shared parameter to your C4GL command line: c4gl -shared d4_*.4gl -o demo4.shared If you attempt to use the -shared option on a platform for which no shared library support is provided, a warning message is displayed to standard error, and compilation continues with the normal static libraries. Many platforms require that dynamically linked (shared library) programs be compiled with position-independent code production from the C compiler. The C4GL script automatically takes care of this for you. One issue that you do need to be aware of is that mixing normal and position-independent code can produce errors. The only thing you need to be careful of is that when you compile with the "-shared" flag, you must recompile all modules from the ".4gl" source if you had previously compiled any without the "-shared" flag. Consider the following example: c4gl myprog.4gl myutil1.4gl myutil2.4gl -o myprog c4gl -shared myprog.o myutil1.o myutil2.o -o myprog.shared Doing this can produce errors, as the objects will not have been compiled with the position-independent option. On the other hand, the following is perfectly acceptable, as the myutil objects will have been compiled with position-independent code (if applicable to your platform): c4gl -shared myprog.4gl myutil1.4gl myutil2.4gl -o myprog.shared c4gl -shared myprog.4gl myutil1.o myutil2.o -o myprog.shared Note: for some platforms, the system linker (ld) enforces much stricter name collision constraints when shared libraries are used. If you have multiple functions in your program with the same name, you may get errors when compiling with shared libraries even if the program links successfully with the static libraries. In such a case, you will need to rename one of the functions to eliminate the name collision. Technical Details ----------------- The name and location of the Informix-4GL shared library will vary depending on the version of Informix-4GL you have, the naming convention for shared libraries on your platform, and the ability of the linker on your platform to locate shared libraries in nonstandard directories. The name of the shared library begins with "lib4gsh" and continues with a three-digit version indicator (e.g. "600" for the 6.00 release). The suffix is platform-dependent; common values are ".so" and ".a". In most cases, the 4GL shared library is located with the other 4GL libraries in $INFORMIXDIR/lib/tools. If your platform does not allow shared libraries in nonstandard directories, your system administrator may have to copy the library to a standard system directory such as /lib or /usr/lib. If this is necessary, this fact should be mentioned in the machine-specific notes for your platform. Note that most, if not all, platforms require that any programs that change their user-id dynamically while running (often referred to as "setuid programs") *and* use shared libraries can *only* access those shared libraries in standard system directories. Therefore, if you have a setuid 4GL program that uses the 4GL shared library, your system administrator must copy or link the 4GL shared library to a standard directory. Run-time Requirements --------------------- Unlike static-linked I4GL programs, I4GL programs that use the shared library must have that library accessible at run time. Most platforms provide an environment variable that instructs the operating system's linking program loader to add one or more nonstandard directories to its shared library search list. Common examples of this variable are LD_LIBRARY_PATH and LPATH. The machine-specific notes provided with I4GL should confirm the appropriate variable name for your platform. All users who wish to run your shared library I4GL application(s) must have this variable set properly in their shell environment. A typical example would be: Bourne or Korn Shells: LD_LIBRARY_PATH=$INFORMIXDIR/lib/tools; export LD_LIBRARY_PATH C Shell variants: setenv LD_LIBRARY_PATH ${INFORMIXDIR}/lib/tools Be sure that all potential users set their environments accordingly, and/or update global environment scripts as applicable for your site. If you develop 4GL applications that are sent out to other systems, those systems must also have the shared library available. All platforms that have 4GL shared library support also have the 4GL shared library included in corresponding runtime versions of Informix-4GL. Be sure to notify your remote users and runtime customers of the environment variable needs mentioned above. DOUBLY-DEFINED GLOBAL VARIABLES =============================== The overview of GLOBALS in the I4GL Reference Manual defines two forms of the GLOBALS statement: one defines variables, the other refers to the file where global variables are defined. The first note clearly states "You may have at most one GLOBALS statement where global variables are defined." This is because I4GL translates the code on the left into, more or less, the C on the right (Sequence A): filea.4gl filea.c ========= ======= GLOBALS a DATETIME YEAR TO SECOND, dtime_t a; b CHAR(20), char b[21]; c DECIMAL dec_t c; END GLOBALS MAIN main() { END MAIN } fileb.4gl fileb.c ========= ======= GLOBALS a DATETIME YEAR TO SECOND, dtime_t a; b CHAR(20), char b[21]; c DECIMAL dec_t c; END GLOBALS FUNCTION f() f() { END FUNCTION } When you link filea.o and fileb.o together, this strictly leads to doubly defined variables, as filea.c and fileb.c both define the variables a, b, and c. However, the vast majority of linkers actually allow this doubly definition, as long as at most one of the definitions includes an initializer. This means that you normally get away with it. What you're supposed to do, of course, is define a file which contains the GLOBALS definitions, and then use that file where you need to refer to those GLOBALS, like this (Sequence B): fileg.4gl fileg.c ========= ======= GLOBALS a DATETIME YEAR TO SECOND, dtime_t a; b CHAR(20), char b[21]; c DECIMAL dec_t c; END GLOBALS filea.4gl filea.c ========= ======= GLOBALS "fileg.4gl" extern dtime_t a; extern char b[21]; extern dec_t c; MAIN main() { END MAIN } fileb.4gl fileb.c ========= ======= GLOBALS "fileg.4gl" extern dtime_t a; extern char b[21]; extern dec_t c; FUNCTION f() f() { END FUNCTION } Now when you link filea.o, fileb.o and fileg.o, there are no doubly defined variables to cause any linker any problems. So much for the theory. What's behind this? The problem is that the Version 6.00 ESQL/C compiler (aka I4GLC3) will generate initializers in both filea.c and fileb.c in Sequence A for each variable which either is a DATETIME or INTERVAL variable or is a compound structure (RECORD or ARRAY or ARRAY of RECORDS) that includes DATETIME or INTERVAL variables. Further, it must do so to ensure that the rest of the code in the file uses the correct type information when accessing the DATETIME or INTERVAL values. However, any 4GL code written in the style of Sequence A no longer links because the global variables are doubly defined. In this example, a would be doubly defined, because the definitions in both filea.c and fileb.c would contain initializers. This means that any Version 4.1x 4GL code which uses Sequence A to define sets of global variables that include DATETIME or INTERVAL variables will compile under Version 6.00, but will not link successfully. The only cure is to use some variation on the correct Sequence B to define and reference the global variables. Legitimate variations --------------------- There are various ways of using globals which look similar to the problematic Sequence A but are actually quite distinct. One of these is the use of module variables. The variables defined with other_stuff are module variables, the equivalent of a static variable in C. The variable other_stuff can be accessed in any function in this file, but it cannot be accessed by any function outside this file. GLOBALS "globals.4gl" DEFINE other_stuff INTEGER Another more complex sequence is possible using multiple source files. It also requires a slightly more flexible interpretation of the statement in the manual "You may have at most one GLOBALS statement where global variables are defined." If you have 5 files, xglobs.4gl, bglobs.4gl, lib.4gl, filex.4gl and fileb.4gl xglobs.4gl ========== GLOBALS DEFINE i DATETIME YEAR TO FRACTION END GLOBALS yglobs.4gl ========== GLOBALS DEFINE j DATETIME YEAR TO FRACTION END GLOBALS lib.4gl ======= GLOBALS DEFINE i DATETIME YEAR TO FRACTION DEFINE j DATETIME YEAR TO FRACTION END GLOBALS FUNCTION lib_function() END FUNCTION filex.4gl ========= GLOBALS "xglobs.4gl" FUNCTION x() END FUNCTION filey.4gl ========= GLOBALS "yglobs.4gl" FUNCTION y() END FUNCTION Provided that your link phase does not try to link either xglobs.o or yglobs.o into an executable which also uses lib.o, then there will be no problems combining filex.o, filey.o and libs.o along with the file defining the MAIN function. The definitions of i and j are in lib.o; filex.o refers to, but doesn't define, i; similarly, filey.o refers to, but doesn't define, j. There are no double definitions, so the program is perfectly legitimate. However, the manual statement needs to be refined; it should read "You may have at most one GLOBALS statement where any particular global variable is defined." Using this technique, or variations on it, programs can be designed to link correctly without double definition problems. The problem is that 4GL does not support multiple GLOBALS files being included in a single 4GL source file. This means that you can end up with a proliferation of files like xglobs.4gl which define a subset of the global variables used by a program. However, this is typically preferable to the alternative scenario of a single monstrous globals file which defines every possible variable and array which could be used by any program in the suite of programs. BUG FIXES ========= Bug 1857: ERROR -4518 DUE TO NOT FREEING TEMPORARY STRING SPACE =============================================================== Error -4518 (The 4GL program cannot allocate any more space for temporary string storage) has been eliminated. Error -4517 (String of length >512 cannot be returned from function calls) has also been eliminated. You should not run into any problem with partially evaluated string expressions and so on fouling up the program. You may, eventually, run out of memory (Error -4339) instead, but the temporary string space (TSS) is recovered whenever a function is exited, or at the completion of a statement with a USING clause or string concatenation operation, so the TSS does not get continuously filled as it used to. The internal operation of the memory allocation system has been completely rewritten. Some internal I4GL routines and structures have been removed as a result of the rewrite of the memory allocation system. Since these are internal routines and structures, their use is undocumented and unsupported. However, it is theortetically possible that some user programs rely on these routines and structures. Any code that relies on the function acdealloc() will fail -- that function has been eliminated. Any code that relies on being able to access alloctab will fail as that structure has been eliminated too. If necessary, you can supply a dummy version of acdealloc() that does nothing -- "acdealloc(){}". You will have to revise any code that accesses alloctab, but you should be able to convert those routines into dummies too. It is difficult to write a program that uses up all the memory, and it would almost certainly have to use a recursive function, such as the Ackerman function on the next page. This code has a deliberate bug in it because it uses a string as the return value, whereas it should be DECIMAL(32,0) -- effectively a giant INTEGER -- to be consistent with the arguments. The program fails under Version 4.11 or earlier versions, but runs successfully under Version 6.00 or 4.12. MAIN DEFINE i DECIMAL(32,0), j DECIMAL(32,0), a CHAR(60) LET i = 3 -- Be wary about increasing this LET j = 3 LET a = "Result of ACKERMAN(", i USING "&", ",", j USING "&", ") = ", Ackerman(i, j) DISPLAY a CLIPPED END MAIN FUNCTION Ackerman(m, n) DEFINE m DECIMAL(32,0), n DECIMAL(32,0), k CHAR(32) CASE WHEN (m = 0) LET k = n + 1 WHEN (n = 0) LET k = Ackerman(m - 1, 1) OTHERWISE LET k = Ackerman(m - 1, Ackerman(m, n - 1)) END CASE RETURN k END FUNCTION This code demonstrates the removal of the limits imposed by error -4517. MAIN CALL func1() END MAIN FUNCTION func1() DEFINE str CHAR(2048), i SMALLINT LET str = "A" FOR i = 2 to 2048 LET str[i] = "A" END FOR LET str = func2(str) DISPLAY "String = ", str END FUNCTION FUNCTION func2(str) DEFINE str CHAR(2048), i SMALLINT DISPLAY "String = ", str CLIPPED LET str = "B" FOR i = 2 to 2048 LET str[i] = "B" END FOR RETURN str END FUNCTION INTERRUPTS AND FOREACH LOOPS ============================ The problem of attempting a FETCH on an unopened cursor is resolved in 6.00 by changing the generated C-code and P-code to check the STATUS after opening the cursor. In Version 4.11 4GL and earlier, the FOREACH loop was effectively translated to the equivalent code shown here: OPEN cursor WHILE (1) FETCH cursor IF STATUS == NOTFOUND THEN EXIT WHILE END IF ...Body of FOREACH loop... END WHILE CLOSE cursor If the prevailing error handling is WHENEVER ERROR CONTINUE, and if for some reason the cursor is not opened successfully, then this code does not check for the STATUS and attempts to FETCH from the unopened cursor, generating error code -400 (Fetch attempted on unopen cursor). One cause of an OPEN failing is the user hitting the interrupt key. If the I4GL program is waiting for a response from the engine when this happens, then error code -213 (Statement interrupted by user) is generated. This code causes the interrupt status to be lost. Note that if interrupt and quit have been deferred, the variable INT_FLAG is always set if the interrupt key is hit, and the variable QUIT_FLAG is set if the quit key is hit. If the interrupt occurs while the application is waiting for a response from the engine, then SQLCA.SQLCODE is set to -213. If, however, the interrupt occurs while the application is doing its own processing and is not waiting for the engine, then error -213 is not necessarily returned, and the data being fetched is valid. Under some circumstances, several rows of data are sent from the engine at a time, and subsequent fetches will not need to wait for the engine. The problem of attempting to implicitly fetch (via FOREACH) on an unopened cursor is resolved in 4.12 by changing the generated C code and P-code for FOREACH to check the STATUS after opening the cursor. The equivalent code is now: OPEN cursor IF STATUS == 0 THEN WHILE (1) FETCH cursor IF STATUS == NOTFOUND THEN EXIT WHILE END IF ...Body of FOREACH loop... END WHILE CLOSE cursor END IF Thus, neither the FETCH nor the CLOSE is executed when the OPEN fails. This avoids modifying the SQLCA structure and losing the information in case of a failure. What happens if the implicit FETCH statement in a FOREACH loop fails? We need to consider the behavior for each of the various WHENEVER ERROR statements which the user can choose for the application: WHENEVER ERROR STOP The program stops with an error, so the CLOSE is not executed. WHENEVER ERROR CONTINUE The program allows the programmer to test STATUS or SQLCA.SQLCODE at the top of the body of the FOREACH loop. The body of the loop is not entered if the OPEN fails, so the only condition tested at the top of the body of the loop is FETCH failures. If the FETCH set STATUS to NOTFOUND, the program will exit the loop automatically and will execute the CLOSE. On a FETCH error, the programmer can optionally CLOSE the cursor and return from the function, or can execute EXIT FOREACH to close the cursor. WHENEVER ERROR GOTO The program goes to the label. The cursor can be explicitly closed by the programmer, who has presumably thought about this before using WHENEVER ERROR GOTO. The CLOSE is not executed by generated code. WHENEVER ERROR CALL The program calls the function. If the function returns, the code will continue as usual, which means in the same general way as WHENEVER ERROR CONTINUE. This shows that the CLOSE statement is not executed in a context in which it clobbers SQLCA or STATUS unexpectedly, so the code does not have to worry about preserving SQLCA or STATUS. Note that the CLOSE statement does unavoidably lose the information contained in SQLCA.SQLERRD[3] about the number of row processed by the SELECT statement. The workaround is to have the program count the number of rows processed. Note that the information may not be reported when the last row is fetched, but at some earlier time, depending on whether the rows are sent from the engine in batches. SUPPORT FOR NESTED RECURSIVE INPUT/DISPLAY STATEMENTS ===================================================== 4GL statements such as CONSTRUCT, DISPLAY ARRAY, INPUT, INPUT ARRAY, and PROMPT use a common underlying data structure called the Input Control Block (ICB). These statements are collectively referred to as ICB statements. Both Version 6.00 and Version 4.12 now support nested and recursive ICB statements in which the parent and the child ICB statements use the same form for accepting and displaying the data. In the case of recursive ICB statements, the parent and the child statements could be the same. 4.12 supports both Direct and Indirect nesting of the ICB statements, where the level of nesting is limited only by the availability of the resources. Direct nesting involves embedding the child ICB statement in one of the clauses such as ON KEY, BEFORE FIELD, AFTER FIELD, etc. of the parent ICB statement. The following code illustrates Direct nesting of INPUT statements: MAIN DEFINE r1, r2 RECORD f1, f2, f3 CHAR(30) END RECORD DATABASE nestedinputDB DEFER INTERRUPT OPEN FORM nest_form FROM "nested_input" DISPLAY FORM nest_form LET INT_FLAG = FALSE IF NOT INT_FLAG THEN INPUT BY NAME r1.* WITHOUT DEFAULTS --Parent INPUT stmt BEFORE INPUT MESSAGE "BEFORE INPUT STATEMENT 1" SLEEP 1 BEFORE FIELD f1 MESSAGE "Input Statement 1 -- BF1" SLEEP 1 AFTER FIELD f2 MESSAGE "Input Statement 1 -- AF1" SLEEP 1 --Child INPUT Statement INPUT BY NAME r2.* WITHOUT DEFAULTS --Child INPUT stmt BEFORE INPUT MESSAGE "BEFORE INPUT STATEMENT 2" SLEEP 1 AFTER INPUT MESSAGE "AFTER INPUT STATEMENT 2" SLEEP 1 ON KEY (CONTROL-W) MESSAGE "IP2: HELP IS NOT AVAILABLE" SLEEP 1 END INPUT --End of Child INPUT stmt LET r2.f1 = "Child INPUT Statement -- ", r2.f1 CLIPPED INSERT INTO table_2 VALUES(r2.*) AFTER INPUT MESSAGE "AFTER INPUT STATEMENT 1" SLEEP 1 ON KEY (CONTROL-W) MESSAGE "IP1: HELP IS NOT AVAILABLE" SLEEP 1 END INPUT --End of Parent INPUT stmt END IF LET r.f1 = "Parent INPUT Statement -- ", r1.f1 CLIPPED INSERT INTO table_1 VALUES(r1.*) MESSAGE "Input Statement -- complete" SLEEP 1 END MAIN In the above nested INPUT statements, the parent and the child statements use the same form for entering data. After the user enters data in fields f1 and f2 for the parent INPUT statement, control is transferred to the child INPUT statement. Once the child INPUT statement is executed, data entered for the child is inserted in table_2. Then control is returned to the parent, and fields f1 and f2 are restored to their original values. Indirect nesting involves invoking a function, which contains the child ICB statement, from the parent ICB statement. Once again, the parent and the child ICB statements use the same form for data entry. The following code illustrates Indirect nesting of INPUT statements: MAIN DEFINE r1 RECORD f1, f2, f3 CHAR(30) END RECORD DATABASE nestedinputDB DEFER INTERRUPT OPEN FORM nest_form FROM "nested_input" DISPLAY FORM nest_form LET INT_FLAG = FALSE IF NOT INT_FLAG THEN INPUT BY NAME r1.* WITHOUT DEFAULTS --Parent INPUT stmt BEFORE INPUT MESSAGE "BEFORE INPUT STATEMENT 1" SLEEP 1 BEFORE FIELD f1 MESSAGE "Input Statement 1 -- BF1" SLEEP 1 AFTER FIELD f2 MESSAGE "Input Statement 1 -- AF1" SLEEP 1 --Indirect Nesting CALL child_inputstmt() AFTER INPUT MESSAGE "AFTER INPUT STATEMENT 1" SLEEP 1 ON KEY (CONTROL-W) MESSAGE "IP1: HELP IS NOT AVAILABLE" SLEEP 1 END INPUT --End of Parent INPUT stmt END IF LET r.f1 = "Parent INPUT Statement -- ", r1.f1 CLIPPED INSERT INTO table_1 VALUES(r1.*) MESSAGE "Input Statement -- complete" SLEEP 1 END MAIN FUNCTION child_inputstmt() DEFINE r2 RECORD f1, f2, f3 CHAR(30) END RECORD LET INT_FLAG = FALSE IF NOT INT_FLAG THEN INPUT BY NAME r2.* WITHOUT DEFAULTS --Child INPUT stmt BEFORE INPUT MESSAGE "BEFORE INPUT STATEMENT 2" SLEEP 1 AFTER INPUT MESSAGE "AFTER INPUT STATEMENT 2" SLEEP 1 ON KEY (CONTROL-W) MESSAGE "IP2: HELP IS NOT AVAILABLE" SLEEP 1 END INPUT --End of Child INPUT stmt END IF LET r2.f1 = "Child INPUT Statement -- ", r2.f1 CLIPPED INSERT INTO table_2 VALUES(r2.*) END FUNCTION It is also legal to perform heterogeneous nesting where the parent and the child statements are entirely different. For example, one can have CONSTRUCT as the parent statement and INPUT as the child statement. Recursive ICB statements were not supported prior to the 4.12 release of I-4GL. This feature provides an extra flexibility to the 4GL programmers while developing their applications. The following sample code illustrates the use of the recursive INPUT statement: MAIN DEFINE r RECORD f1, f2, f3 CHAR(30) END RECORD DEFINE z INTEGER DATABASE recinputDB DEFER INTERRUPT OPEN FORM recurs_form FROM "recursive_input" DISPLAY FORM recurs_form LET z = 0 CALL recursive_input(z, r) END MAIN FUNCTION recursive_input(z1, r1) DEFINE r1 RECORD f1, f2, f3 CHAR(30) END RECORD DEFINE z1 INTEGER LET INT_FLAG = FALSE LET z1 = z1 + 1 IF z1 > 3 THEN RETURN END IF MESSAGE "Recursive Cycle: ", z1 SLEEP 1 IF NOT INT_FLAG THEN INPUT BY NAME r1.* WITHOUT DEFAULTS BEFORE INPUT MESSAGE "BEFORE INPUT STATEMENT 1" SLEEP 1 BEFORE FIELD f1 MESSAGE "Input Statement 1 -- BF1" SLEEP 1 AFTER FIELD f2 MESSAGE "Input Statement 1 -- AF1" SLEEP 1 CALL recursive_input(z1, r1) --Recursive call AFTER INPUT MESSAGE "AFTER INPUT STATEMENT 1" SLEEP 1 ON KEY (CONTROL-W) MESSAGE "IP1: HELP IS NOT AVAILABLE" SLEEP 1 END INPUT END IF LET r.f1 = "Recursive Cycle -- ", z1, r1.f1 CLIPPED INSERT INTO table_1 VALUES(r1.*) MESSAGE "Input Statement -- complete" SLEEP 1 END FUNCTION For every recursive invocation of the function recursive_input(), the same form is used for data entry. A recursive call is made after the user enters data in fields f1 and f2 for each invocation. Before making a recursive call, context is stored in dynamically allocated variables and pushed onto the stack. When the terminating condition for recursion is satisfied, context is popped out of the stack and the form fields f1 and f2 are restored to their original values. It is legal to combine nesting in all its flavors such as Direct, Indirect, heterogeneous, and homogeneous with recursive ICB statements. It is necessary to recompile and re-link applications that use ICB-related statements with 4.12 software to avoid anomalous behavior. WARNING ------- The new nested input features (in particular) allow some operations that can lead I4GL to clean up incorrectly during INPUT, INPUT ARRAY, DISPLAY ARRAY, CONSTRUCT, MENU, and FOREACH loops. Essentially, for any nested statements, an early exit from inside one of the inner statements to one of the outer statements, or a RETURN, means that I4GL does not clean up any statement except the innermost. To illustrate this problem, consider the code below, which is excruciating to read, not to mention of no practical use, but which does show how nested INPUT statements could be used in theory. (There are 9 levels of nested statements in the code.) It also illustrates some of the problems caused by early exits from nested statements. For example, when you do an EXIT FOREACH from inside an INPUT statement nested inside two MENU statements, a FOR loop and a WHILE loop (as shown by the first EXIT FOREACH statement below), then the intervening menus ("ABCDEF" and "XYZ") are not cleaned up correctly, though the INPUT statement itself is handled correctly, and the FOREACH loop cursor is closed correctly. In a future release of I4GL, the nested EXIT, CONTINUE, and RETURN statements may have correct clean-up code generated. This may require a lot of extra code, so early exits from nested statements are not encouraged. Note that GOTO statements, including WHENEVER ERROR GOTO or WHENEVER WARNING GOTO, will not be dealt with properly. If this is a concern, do not use GOTO (see "Go To Statement Considered Harmful" by Edsger Dijkstra, CACM, March 1968). -- @(#)Torture test for I4GL compilers -- @(#)Also a torture test for people reading the C code -- @(#)Also a torture test for C code reformatting programs MAIN CALL f() END MAIN FUNCTION f() DEFINE s CHAR(300) DEFINE y INTEGER DEFINE i INTEGER DEFINE t INTEGER DEFINE a ARRAY[10] OF INTEGER DECLARE c CURSOR FOR SELECT Tabid FROM Systables OPEN WINDOW w AT 1, 1 WITH FORM "xxx" LET y = 0 FOREACH c INTO t FOR i = 1 TO 10 WHILE y < 1000 MENU "ABCDEF" BEFORE MENU HIDE OPTION "B" COMMAND "A" "Absolutely" SHOW OPTION "B" IF a[1] THEN EXIT MENU END IF IF a[1] THEN CONTINUE MENU END IF NEXT OPTION "E" COMMAND "B" "Beautiful" MESSAGE "Thank you" COMMAND "C" "Colorful" MESSAGE "Thank you" COMMAND "D" "Delicious" MESSAGE "Thank you" COMMAND "E" "Exit" EXIT MENU COMMAND "F" MENU "XYZ" COMMAND "X" EXIT MENU COMMAND "Y" INPUT BY NAME y WITHOUT DEFAULTS AFTER FIELD y IF a[1] THEN EXIT FOR END IF IF a[1] THEN CONTINUE FOR END IF IF a[1] THEN EXIT FOREACH END IF IF a[1] THEN CONTINUE FOREACH END IF IF a[1] THEN EXIT WHILE END IF IF a[1] THEN CONTINUE WHILE END IF IF a[1] THEN RETURN END IF IF a[1] THEN EXIT MENU END IF IF a[1] THEN CONTINUE MENU END IF IF a[1] THEN EXIT INPUT END IF IF a[1] THEN CONTINUE INPUT END IF IF a[1] THEN GOTO End_Label END IF IF a[1] THEN GOTO Mid_Label END IF CONSTRUCT BY NAME s ON y AFTER FIELD y IF a[1] THEN EXIT FOR END IF IF a[1] THEN CONTINUE FOR END IF IF a[1] THEN EXIT FOREACH END IF IF a[1] THEN CONTINUE FOREACH END IF IF a[1] THEN EXIT WHILE END IF IF a[1] THEN CONTINUE WHILE END IF IF a[1] THEN RETURN END IF IF a[1] THEN EXIT MENU END IF IF a[1] THEN CONTINUE MENU END IF -- EXIT INPUT is not allowed by the compiler (error 4488) -- IF a[1] THEN EXIT INPUT END IF -- CONTINUE INPUT is not allowed by the compiler (error 4488) -- IF a[1] THEN CONTINUE INPUT END IF IF a[1] THEN EXIT CONSTRUCT END IF IF a[1] THEN CONTINUE CONSTRUCT END IF IF a[1] THEN GOTO End_Label END IF IF a[1] THEN GOTO Mid_Label END IF CALL SET_COUNT(3) DISPLAY ARRAY a TO a.* ON KEY (F3) IF a[1] THEN EXIT FOR END IF IF a[1] THEN CONTINUE FOR END IF IF a[1] THEN EXIT FOREACH END IF IF a[1] THEN CONTINUE FOREACH END IF IF a[1] THEN EXIT WHILE END IF IF a[1] THEN CONTINUE WHILE END IF IF a[1] THEN RETURN END IF IF a[1] THEN EXIT MENU END IF IF a[1] THEN CONTINUE MENU END IF IF a[1] THEN EXIT DISPLAY END IF -- CONTINUE DISPLAY is not allowed by the compiler -- IF a[1] THEN CONTINUE DISPLAY END IF -- EXIT INPUT is not allowed by the compiler (error 4488) -- IF a[1] THEN EXIT INPUT END IF -- CONTINUE INPUT is not allowed by the compiler (error 4488) -- IF a[1] THEN CONTINUE INPUT END IF -- EXIT CONSTRUCT is not allowed by the compiler (error 4488) -- IF a[1] THEN EXIT CONSTRUCT END IF -- CONTINUE CONSTRUCT is not allowed by the compiler (error 4488) -- IF a[1] THEN CONTINUE CONSTRUCT END IF IF a[1] THEN GOTO End_Label END IF IF a[1] THEN GOTO Mid_Label END IF INPUT ARRAY a FROM a.* AFTER FIELD y IF a[1] THEN EXIT FOR END IF IF a[1] THEN CONTINUE FOR END IF IF a[1] THEN EXIT FOREACH END IF IF a[1] THEN CONTINUE FOREACH END IF IF a[1] THEN EXIT WHILE END IF IF a[1] THEN CONTINUE WHILE END IF IF a[1] THEN RETURN END IF IF a[1] THEN EXIT MENU END IF IF a[1] THEN CONTINUE MENU END IF IF a[1] THEN EXIT INPUT END IF IF a[1] THEN CONTINUE INPUT END IF -- EXIT DISPLAY *is* allowed by the compiler (despite error 4488) IF a[1] THEN EXIT DISPLAY END IF -- CONTINUE DISPLAY is not allowed by the compiler -- IF a[1] THEN CONTINUE DISPLAY END IF -- EXIT CONSTRUCT is not allowed by the compiler (error 4488) -- IF a[1] THEN EXIT CONSTRUCT END IF -- CONTINUE CONSTRUCT is not allowed by the compiler (error 4488) -- IF a[1] THEN CONTINUE CONSTRUCT END IF IF a[1] THEN GOTO End_Label END IF IF a[1] THEN GOTO Mid_Label END IF LABEL Mid_label: MESSAGE "You got here? How?" NEXT FIELD y END INPUT END DISPLAY END CONSTRUCT END INPUT COMMAND "Z" MESSAGE "Sucker!" CONTINUE MENU END MENU END MENU END WHILE END FOR END FOREACH LET y = 0 LABEL End_label: CLOSE WINDOW w END FUNCTION PROMPT STATEMENT ================ The PROMPT statement has changed in a couple of minor ways. LENGTH OF DISPLAY LIST ---------------------- In 4.12, the user assumes the onus of ensuring that the length of the display list for the PROMPT statement is smaller than the number of columns on the active window. If the display list is greater than or equal to the number of columns, then error -1146 is generated at runtime. OPTIONS PROMPT LINE ------------------- If the value of the PROMPT LINE specified by the user, using the OPTIONS statement, exceeds the number of rows on the active window then PROMPT LINE is set to its default value, that is, the first row of the window. Consider the following 4GL code that increments the value of the PROMPT LINE in the WHILE loop: MAIN DEFINE ans CHAR(1) DEFINE pline INTEGER DEFINE flag CHAR(1) LET pline = 7 OPTIONS PROMPT LINE pline WHILE pline <> 10 OPEN WINDOW wdw AT 4,6 WITH 7 ROWS, 60 COLUMNS ATTRIBUTE (BORDER) DISPLAY "Rows = 7, PROMPT LINE is set to ", pline at 2, 6 PROMPT "123456789012345678901234567890abcdef" FOR CHAR ans CLOSE WINDOW wdw LET pline = pline + 1 OPTIONS PROMPT LINE pline END WHILE END MAIN In the above 4GL code, the variable pline is set to 7 and PROMPT LINE is set to the value held in pline. Also, a window with 7 rows and 70 columns is opened within the WHILE loop and the value of pline is incremented. Then the user tries to set PROMPT LINE to 8 using the OPTIONS statement. While opening the window in the next iteration, 4GL notices that the value of PROMPT LINE is greater than the maximum number of rows available. Therefore, 4GL silently sets the value of PROMPT LINE to the default value, that is, the first row of the window. UNLOAD STATEMENT SUPPORT FOR HOST VARIABLES =========================================== The UNLOAD statement has been modified to support host variables in the WHERE clause of the embedded SELECT query. The previously recommended workaround for this problem, which dynamically builds the SELECT statement for UNLOAD, is still valid. Following is an example of the workaround that was earlier recommended: DATABASE stores MAIN DEFINE hostvar SMALLINT DEFINE tempsel CHAR(200) LET hostvar = 103 LET tempsel = "select * from customer ", "where customer_num = ", hostvar UNLOAD TO "custfile" DELIMITER ";" tempsel END MAIN Under the new scheme of things, UNLOAD can be done as shown below: DATABASE stores MAIN DEFINE hostvar SMALLINT LET hostvar = 103 UNLOAD TO "custfile" DELIMITER ";" SELECT * FROM customer WHERE customer_num = hostvar END MAIN Do not substitute question marks (?) in place of the host variables to make the SELECT statement dynamic. For example, the following 4GL code is not recommended because it has binding problems: FUNCTION func_unload() DEFINE query CHAR(250) DEFINE file CHAR(20) DEFINE del CHAR(1) DEFINE i INTEGER, j INTEGER, k INTEGER LET i = 100 LET j = 30 LET k = 400 LET del = ";" LET file = "/dev/tty" LET query = "select * from systables where tabid >= ?" " and ncols >= ? and rowsize >= ?" UNLOAD TO file DELIMITER del query END FUNCTION WORDWRAP BUG FIXES ================== The semantics of WORDWRAP have been altered in forms, in CONSTRUCT, and in reports, and the changes are discussed in this section. There is also a brief note concerning AUTONEXT in CONSTRUCT. WORDWRAP in Forms ----------------- This is a change to default behavior. In release 4.10.UC1, it was found that form fields with the WORDWRAP attribute and with the WORDWRAP COMPRESS attributes behaved in a similar fashion. It was also found that the routine used to perform compression was not consistent with the specification. In order to preserve backward compatibility, both Version 6.00 and Version 4.12 has changed the DEFAULT behavior of WORDWRAP fields without any keyword after WORDWRAP; these now behave the same as WORDWRAP COMPRESS. If the attributes for a field reads either WORDWRAP COMPRESS or just WORDWRAP, compress mode is active. If users do not want the compress mode to be active, they must use the new attribute WORDWRAP NONCOMPRESS. After taking into account the change in the default behavior, the wordwrap input routines were modified to implement the behavior specified in the documentation. All user-typed blanks are retained in both COMPRESS and NONCOMPRESS mode. In COMPRESS mode, only line-padding (editor) blanks are eliminated. This change was forecast in the release notes for 4.11.UC1. These changes were made to fix PTS bug number 15434. Also see bug numbers 10166, 14540, and 14179. WORDWRAP in CONSTRUCT --------------------- In version 4.11, when CONSTRUCT was working on a multi-segment field with the WORDWRAP attribute set, the initial input would be displayed in the first segment of the field. When the input no longer fit in the first segment, it would overflow into the second and subsequent segments of the field. However, it also cleared the overflow line at the bottom of the screen, even though no data was displayed there. In both Version 6.00 and Version 4.12, the behavior has been revised so that multi-segment fields are treated the same as single-segment fields; when the first segment is full, the overflow line is used to display the extra data. The extra segments of a WORDWRAP field are not used during CONSTRUCT. Only the first segment and the overflow line are used. This should provide sufficient space for query input. This was bug 14033. Any form field with the WORDWRAP attribute is allowed to span several lines. During work on release 4.12, it was discovered that if the segments of a multi-segment wordwrapped field are not aligned in a single column, then moving backwards from a later segment could cause the cursor to skip some segments entirely, or leave the cursor in odd places inside the segment. Users are advised to avoid overly complex placement of word-wrapped fields. Form field configurations like: [f001 ][f001 ] [f001 ] will probably yield counter-intuitive cursor movement. Columnar form field configurations like the one below will give predictable results. [f001 ] [f001 ] [f001 ] WORDWRAP in REPORTS ------------------- In release 4.11 of RDS, the WORDWRAP attribute in reports did not yield correct results. Any report that attempted to use a PRINT statement in conjunction with WORDWRAP could produce the following symptoms: 1) B13589: Misaligned output. The output would begin at the wrong column. 2) B07942: Extra trailing spaces. This made the PRINT statement appear to ignore the CLIPPED attribute even when it had been specified. 3) B07942: Incorrect default right margin. The correct right margin is position 132. The user is now provided with the full 127 characters of width that are promised in the documentation. All these bugs have been fixed in both Version 6.00 and Version 4.12. AUTONEXT in CONSTRUCT --------------------- When entering criteria during a CONSTRUCT into a field with the AUTONEXT attribute, keying past the form field delimiter does not take the cursor to the next field. During CONSTRUCT, AUTONEXT is ignored so that the user can query for large ranges, alternatives, and so forth. Although the original 4.xx documentation does not mention it, this is the intended behavior of the product. BEHAVIOR CHANGE OF CONSTRUCT WHEN INTERRUPTED ============================================== Version 6.00 (and Version 4.12) of I4GL and RDS introduces a change in the output of CONSTRUCT statements interrupted by the user striking the interrupt key (usually CTRL-C or DEL) or the quit key (sometimes CTRL-\, but often another character). Obviously, this applies only to programs that have executed DEFER INTERRUPT or DEFER QUIT or both; otherwise, an interrupt or quit keystroke terminates the application immediately. In 4.10 and prior releases, interrupting a CONSTRUCT statement (with an interrupt or quit keystroke) produced an output query string that contained the contents of the field buffer at the time the interrupt keystroke was hit. Therefore, if the program did not carefully check the value of int_flag before proceeding, it could miss the fact that the CONSTRUCT had been interrupted and proceed with a bad query. In late 4.10.UE* releases and 4.11, a bug fix changed this behavior such that the output query string reverted to its previous value. This was also somewhat counterintuitive, and if the program failed to check int_flag and take appropriate action, it would repeat the previous query (or fail upon PREPARE if there was no previous uninterrupted execution of that CONSTRUCT). With this release, the behavior has been changed so that a CONSTRUCT interrupted by an interrupt or quit keystroke produces a NULL query string. This minimizes the chance that an unchecked interrupt condition will proceed undetected. Also, the only way a CONSTRUCT can produce a NULL query string is if it was interrupted; this gives an easy means of detecting that an interrupt or quit occurred without having to check both int_flag and quit_flag. (Recall that a successful CONSTRUCT for which the user entered no criteria before striking the Accept key produces the string " 1=1", not a null string.) STATUS VALUE FROM "RUN ... RETURNING" ===================================== The behavior of the value returned from a 4GL "RUN ... RETURNING" clause was different on different machines. Because of OS limitations (see exit(2) or wait(2) in the Unix Programmer's Manual), a range of only 256 values can be returned by the exit status of a command. However, the operating system uses the low order 8 bits of a 16-bit integer for its own information, and the 256 exit status values are stored in the high order 8 bits of the 16-bit integer. When this 16-bit value is stored in a 4GL INTEGER variable, it is always treated as an unsigned quantity, whereas previously it could be treated as either signed or unsigned depending on platform. If the status is stored in a SMALLINT, any exit status between 128 and 255 (and an exit status of -1 is equivalent to 255) is stored as a negative number. For portability, always store the status of the command in an INTEGER. You need to divide the value saved by 256 to get the actual exit status. The low order bits are only non-zero if the shell which ran the command was killed by an unexpected signal. NEW BUILTIN OPERATOR: ORD() =========================== Overview: This function evaluates the first character of a passed character string argument as the corresponding integer number. Syntax: ORD (string-expr) Explanation: ORD is a required keyword. string-expr is a string expression. NOTES: 4GL only evaluates the first character of the passed string. Non-string parameters return the value 0. The parentheses are required. Example: The following assignment assigns the value 66 to the integer ord1. LET ord1 = ORD ("Belladonna") ENVIRONMENT VARIABLES ===================== A number of environment variables have either been added or changed their meaning slightly, or have existed but have not been documented previously. These are documented in this section. You should also look at the environment variables chapters in both the "Informix Guide to SQL: Reference Version 6.0" manual and in the ISQL and 4GL manuals. DBESCWT ------- The environment variable DBESCWT has existed since Version 4.00, and can be used to control the way the Informix tools interpret the sequence of characters sent by the function and arrow keys on some types of terminals. When you press a function key, many terminal types send a sequence of characters that starts with the ESC character. Some terminals send a sequence starting with ESC when the user hits an arrow key. Informix software normally uses the ESC character as the ACCEPT key. This means that after reading an ESC character, the software has to read another character to see whether it is one of the ones that makes up a function or arrow key sequence. But it shouldn't wait indefinitely, and the delay is configurable using DBESCWT. DBESCWT is set to a value between 1 and 60, and it is the number of seconds that the software will wait after receiving the ESC (or ESCAPE) character from the keyboard before deciding that the user has hit ESC rather than having hit a function key or arrow key. When escape sequences are generated by function and arrow keys, they are normally delivered to the application faster than a touch-typist can type so that the application can make a distinction between the special keys and the user typing the characters in the escape sequence. DBESCWT was initially implemented to help customers who had very slow machines. This meant their function keys were seen as escape with a character echoed to the screen. This also occurred intermittently over a slow network. By setting this to a higher number the wait would be longer and the product knows the function key as an escape sequence. This variable should be used sparingly and only on systems with poor response times, or where the software is misinterpreting arrow key sequences. DBLANG: CHANGE OF BEHAVIOR -------------------------- The DBLANG environment variable in version 6.0 uses a different search method from that employed by pre-6.0 versions. In addition, if NLS is enabled and DBLANG is not set, environment variable LANG also affects the search order; in pre-6.0 versions, LANG does not play any role in locating message files. For a full explanation of the new behavior, see the DBLANG entries in either the 4GL or ISQL Version 6.0 manuals. DBFORM: CHANGE OF BEHAVIOR -------------------------- The DBFORM environment variable, introduced in version 4.12, behaves differently in version 6.0 with respect to the search method used for locating form files. In addition, if NLS is enabled and DBFORM is not set, the environment variable LANG also affects the search order; in version 4.12, LANG does not play any role in locating form files. The change mirrors the change made in handling DBLANG. Please note that, as in version 4.12, DBFORM does not affect 4GL programs written by the user; it is solely used by INFORMIX products when accessing internal forms. DBPATH is used to control the location of form files for user programs. For a full explanation of the new behavior, see the DBFORM entries in either the 4GL or ISQL Version 6.0 manuals. SPERISOL and SACEISOL --------------------- Version 4.11 of INFORMIX-SQL provided the ability to run PERFORM forms using dirty read isolation with an OnLine backend. In Version 4.12, this feature has been extended to allow ACE reports and PERFORM forms to run in any isolation level. This feature is of interest to you only if you are running ISQL with OnLine, and is provided mainly to provide compatibility for those who upgrade from Standard Engine to OnLine. The following description assumes an understanding of "levels of isolation" in OnLine databases; you can find this information in the "Informix Guide to SQL: Syntax Version 6.0" manual. The Standard Engine always runs in a mode approximately equivalent to dirty read mode; the default isolation level for OnLine databases with no logging is dirty read, for MODE ANSI databases the default is repeatable read, and for databases with transaction logging the default is committed read. Each mode has a different tradeoff between isolation and concurrency. When you upgrade from a Standard Engine to OnLine, the isolation level automatically changes, as described above. Usually, the new default isolation level is more suitable than the old; however, in some cases, it is preferable if the concurrency level remains the same under OnLine as it was under Standard Engine. This can be accomplished in 4GL by adding code that sets the isolation mode to dirty read, and it can be similarly accomplished in ISQL scripts. To set the isolation level for PERFORM, set the environment variable SPERISOL to one of the following values; similarly, to set the isolation level for ACE, set the environment variable SACEISOL to one of these values: dirty read committed read cursor stability repeatable read In Bourne Shell or Korn Shell, use: SPERISOL="dirty read"; export SPERISOL In C Shell, use: setenv SACEISOL "repeatable read" The isolation level can be specified in uppercase or lowercase (or mixed case), but only a single space is allowed between the words, and there must be no leading or trailing spaces. If the value in the variable is unrecognized, the variable is silently ignored, as is the error from Standard Engine. The environment variables must be set before running the ISQL program (or SPERFORM or SACEGO); trying to set it using a shell escape from within ISQL has no effect. You can use different isolation levels for reports and forms by setting the two environment variables to different values. Note that setting the isolation to dirty read in PERFORM does not allow the user to update a row that is locked by another user, but it would allow the user to see a row that another user has locked. DOCUMENTATION ISSUES ==================== There are a number of issues raised by bug reports which show that some information is missing from the documentation. This section tries to address some of these issues. Three-valued Logic in 4GL ------------------------- The three-valued logic (TRUE, FALSE, NULL) used by 4GL is fully documented in the "Informix-4GL Reference Manual", but some people have not understood all the consequences. This section elaborates on the implications nulls in conditional expressions. In the manual, it is stated that the THEN branch of an IF statement is only executed if the expression evaluates to TRUE. It also points out that if there are NULL values involved, then many of the simple tautologies of 2-valued Boolean logic no longer apply. To amplify on what this means, consider some code. For the purposes of this discussion, variables v1, v2, and v3 are all of type INTEGER, but the comments apply for any type, and for many mixtures of types. -- Example 1 IF v1 = 3 THEN -- Code 1A ELSE -- Code 1B END IF If v1 is not null, then it either does equal 3, in which case code 1A is executed, or it doesn't, in which case code 1B is executed. If v1 is null, then the condition evaluates to UNKNOWN, and since this is not TRUE, code 1B is executed. Now consider this attempt at inverting the logic of example 1: -- Example 2 (faulty inverted logic for example 1) IF v1 != 3 THEN -- Code 1B ELSE -- Code 1A END IF When v1 is not null, then the code in example 2 achieves the same effect as example 1. However, when v1 is null, the expression evaluates to UNKNOWN again, and therefore the ELSE clause is executed. Thus, this is not the direct inverse of example 1. Another way of viewing example 1 is as if it is written with an implicit NOT NULL qualifier on the variable v1: -- Example 3 (equivalent to example 1) IF (v1 IS NOT NULL) AND (v1 = 3) THEN -- Code 1A ELSE -- Code 1B END IF In example 3, if v1 is null, the first part of the condition evaluates to FALSE, the second part evaluates to UNKNOWN, and the overall expression evaluates to FALSE. Applying one of De Morgan's Theorems: NOT (A AND B) == (NOT A) OR (NOT B) to example 3 yields the correct inverted logic for example 1: -- Example 4 (correct inverted logic for example 1) IF (v1 IS NULL) OR (v1 != 3) THEN -- Code 1B ELSE -- Code 1A END IF This code executes in exactly the same way as example 1: if v1 is precisely 3 then code 1A is executed; otherwise, code 1B is executed. This implicit NOT NULL qualifier is the cause of many problems with inverting logic conditions in 4GL. Now consider a slightly more complex condition: -- Example 5 IF v1 = v2 THEN -- Code 5A ELSE -- Code 5B END IF Clearly, if both v1 and v2 contain the same non-null value, code 5A will be executed; otherwise, code 5B will be executed. Note that the description shows that there are implicit NOT NULL qualifiers on both v1 and v2, so the condition is equivalent to: -- Example 6 (equivalent to example 5) IF (v1 IS NOT NULL) AND (v2 IS NOT NULL) AND (v1 = v2) THEN -- Code 5A ELSE -- Code 5B END IF Supplying the inverted logic for example 5 requires us to invert the condition expressed in example 6, so the correct logic for the inverted condition is: -- Example 7 (correct inverted logic for example 5) IF (v1 IS NULL) OR (v2 IS NULL) OR (v1 != v2) THEN -- Code 5B ELSE -- Code 5A END IF This is significantly different from, and much more convoluted than, the simple 2-value logic inversion of example 5: -- Example 8 (faulty inverted logic for example 5) IF (v1 != v2) THEN -- Code 5B ELSE -- Code 5A END IF Extending the condition still further, consider: -- Example 9 IF (v1 >= v2) AND (v1 <= v3) THEN -- Code 9A ELSE -- Code 9B END IF By direct analogy with what has gone before, this is equivalent to: -- Example 10 (equivalent to example 9) IF ((v1 IS NOT NULL) AND (v2 IS NOT NULL) AND (v3 IS NOT NULL) AND (v1 >= v2) AND (v1 <= v3)) THEN -- Code 9A ELSE -- Code 9B END IF And the corresponding inverted condition is: -- Example 11 (correct inverted logic for example 9) IF ((v1 IS NULL) OR (v2 IS NULL) OR (v3 IS NULL) OR (v1 < v2) OR (v1 > v3)) THEN -- Code 9B ELSE -- Code 9A END IF CASE Statements --------------- The CASE statement is equivalent to a series of IF/THEN/ELSE statements. Thus the code in example 12 is equivalent to the code in example 13 -- Example 12 (CASE statement type 1) CASE WHEN v1 < v2 -- Code 12A WHEN v1 > v3 -- Code 12B OTHERWISE -- Code 12C END CASE -- Example 13 (direct equivalent to example 12) IF v1 < v2 THEN -- Code 12A ELSE IF v1 > v3 THEN -- Code 12B ELSE -- Code 12C END IF END IF Suppose the requirements change such that code segments 12A and 12B are modified and become the same code; call it code 12D. It then seems logical to rewrite the code as: -- Example 14 (faulty reworking of example 12) IF v1 BETWEEN v2 AND v3 THEN -- Code 12C ELSE -- Code 12D END IF However, careful analysis of the cases where v1, v2, or v3 are NULL shows that the code in 12C is only executed in a subset of the cases where it used to be executed There are two ways of reworking the code correctly. -- Example 15 (correct reworking of example 12) IF v1 NOT BETWEEN v2 AND v3 THEN -- Code 12D ELSE -- Code 12C END IF -- Example 16 (alternative correct reworking of example 12) IF (v1 IS NULL OR v2 IS NULL OR v3 IS NULL OR v1 BETWEEN v2 AND v3) THEN -- Code 12C ELSE -- Code 12D END IF Again, the implicit IS NOT NULL qualifiers make life much more difficult than they otherwise would be. The I4GL compilers (both C4GL and FGLPC) accept CASE statements with WHEN clauses of the form: CASE variable WHEN "A" OR "B" The condition is translated to: if (variable == ("A" or "B")) and not, as some people have supposed, if (variable == "A" or variable == "B") The compilers also accept code of the form: CASE variable WHEN (variable = "A" OR variable = "B") that is translated to: if (variable == (variable == "A" or variable == "B")) This is a legitimate test (though the result is false unless the value of variable is 0), but it is not what the coder intended. The only method of achieving the required result is to repeat the code as shown: CASE variable WHEN "A" -- code -- WHEN "B" -- code -- Obviously, this should be reduced to the minimum possible, typically by calling a function. Processing of a single field during INPUT or INPUT ARRAY -------------------------------------------------------- The Informix-4GL manuals contain a detailed description of the sequence in which the various BEFORE FIELD and AFTER FIELD control blocks (and for INPUT ARRAY, the BEFORE and AFTER ROW or INSERT or DELETE control blocks), but there is no single point which describes what happens while the cursor is in a single field. There are many things to consider. These include: -- Data type -- Underlying database column * NULLS allowed, NOT NULL -- Attributes in the form * REQUIRED * NOENTRY * UPSHIFT/DOWNSHIFT * WORDWRAP NONCOMPRESS, WORDWRAP COMPRESS * PICTURE * FORMAT * WITHOUT NULL INPUT The data type for the field controls the range of acceptable input. The acceptable values for the various data types is documented in many of the Informix manuals. See for example the Informix Guide to SQL Reference Version 6.0, Chapter 3 (and also Chapter 4 for information on environment variables which modify the set of acceptable values). Whether the column accepts nulls or not determines whether the field will allow you to enter a null value, although this can be overridden by the program. If the column does not accept nulls, then the field may not be left null (blank) when the accept key is hit. If one field is blank but shouldn't be, then the cursor is returned to that field with the message "This field requires an entered value". This effect can also be achieved by adding the REQUIRED attribute to the form. This can be valuable when dealing with FORMONLY fields which should have data entered. You can override this effect by using EXIT INPUT in an AFTER FIELD clause. Note that a required field can be left blank until the ACCEPT key is hit. If the field may not be left blank after the cursor has entered it, then the AFTER FIELD block must enforce this. Note that if a field is left blank, or with precisely the image of the PICTURE attribute, it is treated as NULL and the input variable is set to NULL, unless of course the REQUIRED attribute is effective. A field can be specified as NOENTRY. Even if this field is listed in an INPUT statement, the cursor will not enter this field but will skip over it. Note that fields associated with SERIAL columns are automatically NOENTRY fields. The NOENTRY attribute does not stop the field being used by CONSTRUCT. The UPSHIFT or DOWNSHIFT attribute forces all characters entered in a field to either upper case or lower case. The WORDWRAP attribute is discussed elsewhere in this document. The PICTURE attribute controls the input format for a field, and has no effect on the data displayed in the field. If the user does not type anything into the field, it is treated as NULL. However, once any data has been typed into the field, there is no way in general to leave the field without entering a valid value (B12412). By contrast, the FORMAT attribute controls the display format for a field and does not constrain the input format. For example, a data could be entered as 940506 and displayed as 1994-05-06. WITHOUT NULL INPUT is an attribute of the form rather than of a field. If the form contains this attribute, then all non-blob fields will have a default value substituted in place of NULL at the end of the input. The REQUIRED attribute overrides this default. The default value is 0 for numbers and intervals, blank for character strings, 31 December 1989 for dates, and 1989-12-31 23:59:59.99999 for datetime year to fraction(5). This was introduced primarily as a transition measure with ISQL 2.00 (upgrading from ISQL 1.10) and I4GL 1.00 (a new product), but has survived ever since. See B12268 below. Number of Keys in a COMMAND KEY Clause -------------------------------------- MENU has always had a limit on the number of keys that can be bound to a given COMMAND KEY() clause, but this limit was never properly documented. This limit is four keys per command clause. For example: MENU "Main Menu" COMMAND "Option 1" "Option 1 Description" ... COMMAND KEY("a", "up", CONTROL-F, F35) {LEGAL} ... COMMAND KEY("b", "down", CONTROL-B, F36, F10) {ILLEGAL - 5 keys} ... If you exceed this limit, RDS returns error -4457 at compile time. I4GL returns an error at phase 2 of the compile of the form: i4glc2: file "cmkey.ec", line 31: You may have at most 4 keys in the key list In a future release, the limit may be expanded; even if it is not expanded, a more helpful error message will be produced by compiled 4GL. Using the FREE Statement ------------------------ The FREE statement can be used to release space acquired for blobs and for releasing the space associated with statements and cursors. The handling of blobs has not changed. In 6.00 4GL, you should FREE both statements and cursors to release all the space they use. You can FREE a statement after a cursor has been declared from it, and you can still use the cursor. See the "Informix Guide to SQL: Syntax Version 6.0" manual on FREE. Note that the example does not show freeing both the statement and the cursor, but the accompanying text makes it clear that you should, and experiments with memory monitors support this. The USING Clause and the FORMAT Attribute ----------------------------------------- In 4GL it is possible to specify the output format of numbers and monetary values via the USING clause or by the FORMAT attribute. These programming constructs have been tested and do work for all European locales; however, there are some bugs in the interaction of these features and DBFORMAT. When DBFORMAT is set to a value that specifies a leading currency symbol that is longer than 5 characters, a USING clause (or equivalently a FORMAT attribute) for money (e.g. "$$$,$$$.##" or "###,###.##@@") can result in output that is missing some of the least significant digits. Several work-arounds exist. One is to consider whether the currency symbol is appropriate, preferably switching to an alternative of 5 characters or less. The preferred solution is to switch over to a purely locale-based formatting environment. This solution involves obtaining the appropriate locale and the setting LANG to refer to this locale (e.g. setenv LANG de) and then turn off DBFORMAT (e.g. unsetenv DBFORMAT). If you still want to use DBFORMAT, you may simply add more digits to the USING clause (e.g. "$$$,$$$.###" instead of "$$$,$$$.##"). Behavior of ISQLDEMO -------------------- Bug No. Effect Short Description _______ ______ _________________ 23158 MALFUN ISQLDEMO DOES NOT INSTALL ALL THE REQUIRED FILES AND LIBRARIES, NOR DOES IT DESCRIBE HOW TO COMPILE AND INSTALL FUNCTIONS Bug 23158 was logged against isqldemo but was found to be a documentation issue. The ISQLDEMO script does not try to build the 4 different custom runners that would be required to enable the user to run the 4 forms and reports that need custom runners. The information on how to compile these custom runners is contained in the INFORMIX-SQL Reference Manual. The reports that will not run are a_ex1.ace and a_ex2.ace; the forms that will not run are p_ex1.per and p_ex2.per. The ISQL program cannot run those forms or reports directly. The nearest that can be achieved is to use either the shell escape or to run them from a User Menu option (which would have to be of type "P"). You can compile them without error, but when you try to run them, you will get an error message stating that some functions have not been defined. Behavior of STARTLOG ==================== Bug No. Effect Short Description _______ ______ _________________ 14426 MALFUN STARTLOG() DOESN'T RETURN MODULE NAME OR LINE# FOR ERROR -4500 19764 MALFUN CALL STARTLOG NOT DISPLAYING MODULE OR LINE NUMBER IN I4GL Bugs 14426 and 19764 were logged against the STARTLOG function, but were found to be a documentation issue, and are effectively duplicates of each other. The documentation states that the error record will always contain the line number and module name where the error occur, as well as the date and time when the error occurred. In some circumstances, such as error -4500, which occurs inside an operating system function called by I4GL, the line number and module name is not available. By contrast, this information is always available in RDS. GUIDELINES ON 4GL REPORT WRITING ================================ This section documents certain practices that are prohibited or are at least heartily discouraged within report functions, and it gives some guidelines with respect to usage of module global or program global variables within reports. Note that the compilers do not allow the following statements within report functions. However, these statements can be executed by functions that are called from within the body of a report: * PROMPT * INPUT * INPUT ARRAY * DISPLAY ARRAY * CONSTRUCT Using RETURN in a Report is not Appropriate ------------------------------------------- The RETURN statement is not appropriate for use in a REPORT function at any time; it is designed for use in regular 4GL functions only. The compilers do, however, allow the programmer to use RETURN in a REPORT. If you wish to stop processing of a given report without aborting the program altogether, the best method is to set a global flag that is tested in your report driver function (where the OUTPUT TO REPORT statement(s) are located). If the flag value indicates a problem, finish the report and ignore the output. If your report uses ORDER BY (without the EXTERNAL keyword), or if you use a WHERE clause with any aggregate (as described in the Informix-4GL Reference Manual), or if you use non-GROUP aggregates in any control block other than the ON LAST ROW control block, the report is processed as a "multi-pass" report. This means that the report function's control blocks do not execute until all data has been gathered and the FINISH REPORT statement has been reached in the report driver function. At this point, from the 4GL programmer's perspective, the report function executes as a unit, and it cannot be programmatically aborted from within (since you cannot use the RETURN statement). Better methods for allowing the 4GL programmer to abort report processing are being studied for implementation in a future release. Parameterless Reports --------------------- Parameterless reports are not illegal and are occasionally useful for very specialized reports, but their behavior is not intuitively obvious. In particular, aggregates only work reliably when applied to parameters to reports, and not when they are applied to global or local variables. Additionally, ordering has to be done on parameters. Global Variable Usage --------------------- The use of module global or program global variables in reports is legal, and prudent use of globals can provide performance benefits. However, the use of globals in multi-pass reports may yield unexpected results. Some guidelines are presented here: If you know that your report is not a multi-pass report (as defined above), and you refer to variables that are not used as control information in the report (e.g., they are not referenced in BEFORE/AFTER GROUP OF clauses or in aggregates; they are merely printed), any such variables can be global variables. In fact, passing long character strings as global variables instead of report parameters can result in an improvement in performance, if these other conditions are met. Also, any global variables that will not change in value while generating the report may be freely used even in multi-pass reports if these other conditions are met. In a multi-pass report, most references to a global variable use the value of the variable when the FINISH REPORT statement is executed. This yields unexpected results if the global variable value changes between OUTPUT TO REPORT statements. Temporary Tables Created by Multi-pass Reports ---------------------------------------------- A multi-pass report creates a temporary table to hold the data as rows are sent to the report by OUTPUT TO REPORT statements. The temporary tables are created by prefixing the report name with "t_". In version 4.11 and earlier versions, a report that had a name of 17 or more characters resulted in an attempt to create a temp table with 19 or more characters in its name, leading to a runtime error from the engine. This is no longer a problem in version 4.12 because the names of the temporary tables are truncated at 18 characters. The names of reports that run concurrently should still be distinct within 16 characters, as otherwise the second one started will encounter "table exists" errors. You should also be wary of designing a database with tables whose names start "t_" as this restricts the names that can be used for report functions in a non-obvious way. Note that the temporary tables are inherently private to the user running the report, so there is no conflict with multiple users running the same report, nor with the same user running the same report in different windows. B. Selected Notes from Earlier Releases Notes from the 4.11 Release =========================== CONSIDERATIONS FOR FUTURE RELEASES ---------------------------------- Informix Software's internal Compatibility Guidelines recommend that features evolving or being made obsolete be documented in the release notes of the previous release. Our existing policy states that undocumented features are unsupported in the current release and may "disappear" in future releases. It is too early to categorically list such candidate features, but we can indicate some areas of functionality that may be altered in a future release: 1. User calls to the "_ef..." functions in the 4GL libraries libforms.a and libnforms.a. These may be replaced by more fully-featured and supported user-accessible library, supported in both compiled 4GL and RDS. This includes _eflastkey, an undocumented feature which is often used by developers, and that has now been fully implemented as the 4GL fgl_lastkey() function. _eflastkey still works in 4.10, but may not in a future release, so we strongly encourage conversion to the supported function. 2. Direct calls to our curses implementation (e.g., waddch(), wmove(), wrefresh()) may not be supported in a future release. 3. User identifiers should never begin with an underscore, to avoid conflicts with Informix's (or another product's) library naming conventions (e.g., C functions and variable names). Note that all features and recommendations described here are subject to change without notice. COMPILE-TIME AND LIBRARY FUNCTIONS: NAMING CONVENTIONS ------------------------------------------------------- The 4.10 release of 4GL introduced several compile-time and library functions that are fully documented in the Informix-4GL Version 6.00 manuals. 4GL developers should avoid using the "fgl_" prefix, to forestall any future library function name conflicts. In future releases, this prefix may be reserved. API macros 4GL Functions ---------- ------------- fgl_call() fgl_getenv() fgl_end() fgl_keyval() fgl_exitfm() fgl_lastkey() fgl_start() field_touched() get_fldbuf() Notes from the 4.10 Release =========================== Compatibility Issues -------------------- Using Version 4.10 and Older Versions of INFORMIX-4GL and INFORMIX-SQL ---------------------------------------------------------------------- This section discusses general improvements or corrections to the products that may affect existing applications. The topics largely address the areas of ANSI-compliant syntax and general error handling behavior. 1. The 4.10.UC1 version of the database engines introduced enforcement against redundant specifications of table names in INSERT and UPDATE statements, per ANSI requirements. For example, the following statements were allowed in 4.00 and earlier but would produce syntax errors due to the redundant table names when used with a 4.10 and higher database engine: INSERT INTO tab1(tab1.col1, tab1.col2) VALUES (val1,val2) ^^^^ ^^^^ UPDATE tab1 SET (tab1.col1, tab1.col2) = (a,b) ^^^^ ^^^^ This change was made effective for both MODE ANSI and non-MODE ANSI databases. Effective with version 4.10.UE1 of the database engines, the redundant table name no longer produces error messages in non-MODE ANSI databases. This helps avoid problems for users who are migrating existing applications to the 4.10 engines. However, we recommend against including redundant table names, since these do not provide any benefit and can limit portability of your applications to MODE ANSI environments. Therefore, the above examples should be corrected to read: INSERT INTO tab1 (col1, col2) VALUES (val1,val2) UPDATE tab1 SET (col1, col2) = (a,b) 2. A change was made in the behavior of MODE ANSI so that cursors not explicitly declared "FOR UPDATE" are still treated as update cursors. This is correct ANSI behavior. However, if the cursors are not declared for update, no update lock is put on the row when it is read. As a result, users may get lock errors when they try to update the row. 3. For MODE ANSI databases, if any statement returns no rows (ie, no rows meet the search criteria), the return code is now 100, instead of 0 as it is for databases that are not MODE ANSI. 4. The ANSI standard requires that all identifiers, including owner names and login names, be in uppercase letters. In MODE ANSI, you must enclose lowercase and mixed-case identifiers in quotes if you want to preserve the case. Otherwise, all owner and login names (except informix and public) are shifted to uppercase. 5. Cursor Manipulation The following rules are adhered to in the 4.10 release and are in effect for all later releases: CLOSE CURSOR --------------- Cases that result in an error: a. Closing a cursor that has been declared but never opened. b. Closing an already closed cursor in a MODE ANSI database. Cases that do NOT result in an error: a. Closing an already closed cursor in a non-MODE ANSI database. FREE CURSOR/STATEMENT ID ------------------------ Cases that result in an error: a. Closing a FREEd cursor. Cases that do NOT result in an error: a. FREEing a cursor or statement-id more than once. b. FREEing a cursor that has been declared but never opened. Additional Rules ---------------- In addition to the preceding rules, the following also apply: a. A statement-id that has been FREEd must be PREPAREd again in order to be used again. b. A cursor that has been FREEd must be DECLAREd again in order to be used again. 6. CONSTRUCT/END CONSTRUCT within INPUT If the current application is using a CONSTRUCT within an INPUT statement, the CONSTRUCT statement needs to be terminated with an END CONSTRUCT statement, to properly assign ON-KEY clauses to their INPUT statements. Here is an example: INPUT BY NAME col1, col2, col3 ... ON KEY (CONTROL-M) CONSTRUCT BY NAME query on col1, col2 END CONSTRUCT -- Needed ON KEY (CONTROL-Y) ... END INPUT USE OF USER MENU WITH MODE ANSI DATABASES ----------------------------------------- Because of the owner identification of objects in MODE ANSI databases, the person who first creates the user menu in ISQL by choosing the Modify option is the only user who can change the menu. All others attempting to modify the user menu receive an error message. USE OF UPSCOL WITH MODE ANSI DATABASES -------------------------------------- By using UPSCOL, a user can store default attributes and validate data in syscolval and syscolatt only for tables owned by the user. A form that refers to tables owned by other users uses the defaults and attributes defined by the other users. Similarly, the INITIALIZE statement uses the defaults defined by the owner of the table in which the column resides. IV. BUGS FIXED IN THIS RELEASE A total of 160 bugs which had previously been visible to customers were fixed in Version 6.00. This includes 125 bugs also fixed in 4.12. It excludes bugs which were never seen by customers (bugs found during development and testing), and also bugs which were fixed in an earlier version than 4.12 but which were not shown to be fixed until after 4.12 was released. There are quite a lot of bugs in both categories. The following bugs were fixed in 4GL: Bug No. Effect Short Description _______ ______ _________________ 01857 MALFUN ERR -4518 DUE TO NOT FREEING TEMP STR SPACE 02731 WKARND .4GE PERMISSIONS NOT CONSISTENT I4GL/C4GL. 03705 COSM I4GL SCREEN IS NOT REFRESHED AFTER RETURNING FROM QUERY LANGUAGE. 07360 MALFUN UNLOAD STMT WITH HOST VARIABLES IN WHERE CLAUSE FAILS W/-202 ERR 09874 RESULT C4GL GENERATES CHAR STRINGS OF LEN 1 IF DEFINE LEN > 32767 10465 WKARND CONTINUE INPUT DOES NOT RETURN THE CURSOR TO THE SAME FIELD 10509 MALFUN NO DISPLAY WHEN FORM LINE 1 AND FIRST FIELD IS WORDWRAP 10622 CORRPT NATIONAL CHARS IN FORM DISPLAYED INCORRECT WHEN REENTERING FIELDS 10624 CORRPT DATA ENTRY NOT MANDATORY IF FIELD REQUIRED AND DATABASE NOT NULL 10739 RESULT 4GL ROUNDS UP MONEY TYPE AND SHIFTS OUTPUT TO RIGHT 1 POSITION 10978 MALFUN FGLPC DOES NOT CLOSE DATABASE BEFORE COMPILING NEXT FILE 11336 WKARND ERROR LINE REAPPEARS AFTER BEING OVERWRITTEN BY FORM ERROR 11350 WKARND PREVIOUS ATTRIBUTE KEPT ON LONG CHAR DISPLAY USING WORDWRAP 11580 RESULT EXTRA HEADER ON SECOND REPORT IF SKIP TO TOP OF PAGE ON LAST ONE 11959 MALFUN 4.0 RDS AND C4GL COMPILERS ADD QUOTES TO OWNER NAMES. 12071 RESULT INCONSISTENT VALUES FROM "RUN ... RETURNING" - SOMETIMES SIGNED 12342 MALFUN LAST WORD IN WORDWRAP FIELD IS NOT ACCESSIBLE WITH ARROW KEYS 12524 MALFUN GRANT PRIVILEGES TO QUOTED USER OF MODE ANSI DB FAILS IN 4.00 12836 MALFUN DEFER QUIT DOES NOT WORK 13266 MALFUN MOD BY ZERO PRODUCES CORE DUMP 13330 MALFUN DISPLAY WITHIN BEFORE INPUT CAUSES FIELD_TOUCHED TO REPORT TRUE 13977 MALFUN COMPILED 4GL CORE DUMPS WHEN ENCOUNTERING AN EMPTY MENU TITLE 14033 MALFUN WORDWRAP FIELD IN CONSTRUCT DISPLAYS UNNECESSARY OVERFLOW LINE 14260 CORRPT INPUT ARRAY INSERT LEAVES PREV VALUES IN INSERTED ROW 14847 MALFUN 4GL DOES NOT USE "DBLANG" TO ACCESS ITS HELP MESSAGES 15051 WKARND UNLOAD STATMENT IN 4GL DOESNT RECOGNIZE VARIABLES IN WHERE CLAUSE 15059 CORRPT INPUT ARRAY WITHOUT DEFAULTS: F1 & F2 COPY OLD DATA INTO NEW ROW 15148 NA FEATURE REQUEST: INTRODUCE A 'DBLANGFORM' ENVIRONMENTAL VAR. 15246 MALFUN 203 PRINT SUM() STATEMENTS IN THE ON LAST ROW WON'T COMPILE 15379 MALFUN TERMCAP WITH SG#=1 CAN OPEN WINDOWS WITH 77 AND LESS COL NOT 78 15381 MALFUN OPEN WINDOW X AT ROW, COL WHERE COLUMN IS 1 THRU N NOT 2 THRU N 15410 RESULT TENTH DIGIT GETS SQUASHED ON MONEY DATA TYPE IN 4.1, NOT IN 4.0 15434 CORRPT EDITOR BLANKS NOT STORED WHEN USING UNCOMPRESSED WORDWRAP IN FORM 15710 RESULT FGL_KEYVAL WITH SUBSTRING CAUSES CHAR AFTER SUBSTRING TO BE NULLL 15930 WKARND START REPORT .. TO PIPE CLEARS SCREEN IN 4.10 15976 MALFUN CLOSE WINDOW GETS -1141 AFTER INTERRUPT IN CONSTRUCT 16188 MALFUN USE OF INVALID STRUCT EFWINDOW BY 4GL C CODE GENERATOR 16763 MALFUN UNABLE TO READ THE COMPILED VERSION OF A FORM. 17795 WKARND WITHOUT NULL INPUT CLAUSE IN FORM REQUIRES INPUT 17956 MALFUN ERROR 4322 FROM COMPILE OF COMPLICATED PROGRAM W/MULTIPLE TABLES 17975 WKARND CANNOT DISPLAY 80-COLUMN WINDOWS 18456 MALFUN CORE DUMPS ON ENTRY INTO FIELD WITH DEFAULT & INCLUDE ATTRIBUTE 18673 WKARND DELETING LAST ROW OF INPUT ARRAY DOESN'T ERASE UNTIL UP-ARROW". 18762 WKARND COLUMN NAMES STARTING WITH "_" WILL NOT COMPILE 18993 WKARND DBFORMAT DOESN'T WORK CORRECTLY WITH INCLUDE ATTRIBUT 19472 WKARND CANNOT INTERRUPT FOREACH WITH OPTIONS SQL INTERRUPT ON 19557 WKARND THE COMMENT LINE IS BLANKED OUT WITH WORDWRAP ATTRIB. ON CONSTRUC 19617 WKARND REPORT TO PIPE NAMED "LPR" REVERTS TO DBPRINT/DEFPRINT SETTING 19768 WKARND PICTURE ATTR ON DATETIME FIELD DOESN'T ALLOW NULL INPUT 20073 MALFUN INVISIBLE ATTR DEFINED IN FORM DOES NOT WORK DURING INPUT STMT 20646 ERRMSG BYTE BLOB WITH NO PROGRAM = SAYS USE ! WHEN ! HIT 20652 WKARND PRINT STR WORDWRAP RIGHT MARGIN X WITH X INTEGER TRIGGERS ASSERT 20900 WKARND C4GL REPORTS PRINT (LEFT MARGIN) SPACES ON FIRST LINE OF TOP MARG 20940 MALFUN DUFF C GENERATED: FOR LOOP HAS INCREMENT/DECREMENT & TYPE INTEGER 21202 MALFUN F4GLC GENERATES ERRONEOUS ESQL/C FOR LET X = F(R.A THRU R.N) 21272 WKARND FGLPC ALLOWS TIME(X) AND NOW AS BUILT-IN FUNCTIONS; FGLC DOESN'T 21330 MALFUN FGLPC ACCEPTS DISPLAY ASCII 3; FGLC2 DOESN'T 21358 WKARND UNDOCUMENTED KEYWORD NOW DOESN'T WORK 21359 WKARND BUILT-IN FUNCTION TIME ACCEPTS ARGS IN RDS BUT NOT C4GL 21360 WKARND UNDOCUMENTED KEYWORD NOCR ACCEPTED BY C4GL BUT NOT RDS 21362 NA MISSING INVERSE FUNCTION OF ASCII 21479 WKARND RUN "SLEEP 30; SOMETHING ELSE" WITHOUT WAITING WAITS 30 SECONDS 21480 WKARND FGLGO ALLOCATES BUT DOES NOT FREE MEMORY WHENEVER A CMD IS RUN 21484 WKARND FGLC ALLOWS: RUN CMD WITHOUT WAITING RETURNING VAL; FGLPC DOESN'T 21729 CORRPT BLOB VARIABLES UNUSABLE AFTER BEING INITIALIZED TO NULL 21737 MALFUN REPORT OF 17 OR MORE CHARS WITH INTERNAL SORT FAILS AT RUNTIME 21747 MALFUN CONSTRUCT BY NAME GIVES A CORE DUMP, IF THE FLD IS NOT DEFINED 21750 MALFUN CORE DUMP W/INPUT FROM ONE FORM, DISPLAY ANOTHER THEN EXIT INPUT 21823 WKARND USING VARCHARS RESULTS IN NULL CHARACTERS IN 4GL REPORTS. 21825 WKARND UPSHIFT/DOWNSHIFT READ BEYOND ALLOCATED SPACE 21970 MALFUN CORE DUMP WITH INPUT ON SAME STRUCTURED FORM 21975 MALFUN UNLOAD COMMAND CAUSING CONCATENATION PROBLEMS IN 4GL 22112 WKARND 4GL REPORTS: PRINTING A NULL DATETIME OR INTERVAL PRINTS NO SPACE 22198 RESULT REVERSE ATTRIBUTE IN A FORM YIELDS THE DISPLAYED VALUES INVISIBLE 22303 CORRPT SETTING A VARCHAR IN A FUNCTION LINKED IN AT COMPILE TIME (A .O FILE) DOES NOT CONTAIN THE VALUE WHEN IT RETURNS TO THE CALLING FUNCTION 22426 MALFUN IF SUBSTRING RETURNED FROM FUNCTION IS CONVERTED TO DECIMAL, PURIFY REPORTS ABR AND ABW 22489 MALFUN BLOB VARIABLES UNUSABLE AFTER BEING INITIALIZED TO NULL 22610 CORE ORDER EXTERNAL BY WITH MORE THAN 8 FIELDS CORE DUMPS IN RDS. DUP OF B13346. 22697 CORE INTERRUPT IN CONSTRUCT CLOBBERS ICB, YIELDS SEG FAULT IF CONSTRUCT RERUN, ALSO GIVES OLD QUERY STRING BACK. 22738 ERRMSG ERR_GET DOES NOT RETURN TABLE NAME WHEN SQLCODE PASSED IS -206 23186 MALFUN STATUS IS STILL SET TO ZERO WHEN UNLOAD STATEMENT IS FAILED 23262 MALFUN PROMPT WITH NO INPUT SUPPLIED GIVES UMR FROM PURIFY 23468 MALFUN THE DATETIME LIMITS ON A DATETIME VARIABLE USED IN A STRUCTURE WITH A LET X.* = Y.* CORRUPTS THE DATETIME VARIABLE IN STRUCTURE X 23560 WKARND C4GL FAILS TO CATCH A SYNTAX ERROR IN "DECLARE XX CURSOR ... FOR UPDATE OF" 23705 MALFUN DECIMAL VALUE SELECT FROM TABLE ASSIGNS WRONGLY TO LARGER PRECISION/SCALE VARIABLE 23707 MALFUN REVERSE AND INVISIBLE ATTRIBUTES USED TOGETHER ON SCREEN FIELD WILL CAUSE INVISIBLE NOT TO WORK IF SCROLL BACK TO THE FIELD - BOTH RDS/4GL 24040 RESULT THE DEFAULT VALUE OF THE SCREEN FORM FOR DATA TYPE "DECIMAL" SUBSTITUTES A VALUE OF ZERO "0" FOR THE NUMBER IN THE THIRD DECIMAL PLACE. 24079 ERRMSG 4GL DOES NOT RETURN CONSTRAINT NAME IF VIOLATED REFERENTIAL CONSTRAINT. 24162 MALFUN FORM FIELDS IMPROPERLY DISPLAYED ON VT100 TERMINAL EMULATION 24748 MALFUN USING "<>" AS DELIMITER IN A FORM CAUSES PROBLEMS WITH REVERSE