HPlogo ALLBASE/SQL C Application Programming Guide: HP 3000 MPE/iX Computer Systems > Chapter 1 Getting Started with ALLBASE/SQL Programming in C

Developing ALLBASE/SQL Applications

» 

Technical documentation

Complete book in PDF
» Feedback

 » Table of Contents

 » Index

The basic steps in developing ALLBASE/SQL applications are as follows:

  • Create a source file.

  • Preprocess the source file.

  • Compile and link the program.

These steps, shown in Figure 1-1, are further described in the following paragraphs.

Figure 1-1 Creating an ALLBASE/SQL C Application Program

[Creating an ALLBASE/SQL C Application Program]

Creating Source Files

Using an editor, you create one or more files containing C source code and SQL commands, which are said to be embedded in the program. You can use multiple source files, but each file containing embedded SQL statements must be separately preprocessed.

Using Embedded SQL

The following SQL statements can be embedded in your program:

  • Host variable declarations.

  • INCLUDE SQLCA statements to let ALLBASE/SQL pass return codes to your program.

  • A CONNECT command specifying the name of a DBEnvironment.

  • BEGIN WORK and COMMIT WORK commands to delimit transactions (Note that if a transaction is not already started, any SQL command will automatically issue an implicit BEGIN WORK.).

  • SELECT, INSERT, UPDATE, or DELETE commands; or cursor operations.

  • Explicit or implicit error handling.

The ALLBASE/SQL Reference Manual describes the complete syntax for each kind of SQL statement.

Some SQL statements can only be used in application programs. These include the cursor commands (DECLARE, OPEN, FETCH, REFETCH, UPDATE WHERE CURRENT, DELETE WHERE CURRENT, and CLOSE); the bulk commands (BULK SELECT and BULK INSERT); and the error handling commands (WHENEVER and SQLEXPLAIN).

Moreover, some of the statements have a different effect when used in an application program than when used interactively. For example, the SELECT command in ISQL may be used when you wish to retrieve multiple rows, but in an application program a simple SELECT that retrieves more than one row results in an error.

General Rules for Embedding SQL

ALLBASE/SQL C programs often follow a pattern where a main program segment calls functions that include the embedded SQL code.

Declaring Special Data Structures

You must include the following instruction to the ALLBASE/SQL preprocessor in the global declarations area of each source file:

   EXEC SQL INCLUDE SQLCA;

This incorporates into your program a data structure for handling return codes from ALLBASE/SQL, including numbered error conditions. You can use the information in the sqlca (SQL Communications Area) to test and branch. Refer to Chapter 4, "Runtime Status Checking and the sqlca," for complete information about using the sqlca.

If your program includes dynamic query processing for the FETCH command with a USING DESCRIPTOR clause, add the INCLUDE SQLDA statement to your global declarations, and define the appropriate data buffer and format array. These elements are described fully in Chapter 8.

All other SQL commands may appear in any part of your program.

Declaring Host Variables

In addition to the normal variable declarations, the source file contains variable declarations for host variables. These can appear wherever declarations are legal. However, it is recommended that you include them at the beginning of the file, since they are translated into global variables by the preprocessor anyway. If more than one source file references the same set of variables, you must declare them separately in each file, and you must preprocess each file separately. See Chapter 2 for more details. Host variable declarations appear within a pair of SQL statments:

   EXEC SQL BEGIN DECLARE SECTION;

     .

     .

   EXEC SQL END DECLARE SECTION;

Host variables can appear both in the embedded SQL statements in your code and in ordinary C statements. When they appear in embedded SQL statements, you prefix them with a colon, as shown in this example:

   EXEC SQL SELECT PartName, SalesPrice

        INTO :PartName, :SalesPrice

        FROM PurchDB.Parts;

Host variables are treated fully in Chapter 3.

Skeleton Program

The skeleton program in Figure 1-2 illustrates the relationship between C constructs and embedded SQL commands in an application program. SQL commands may appear in the program at locations indicated by the comments.

Figure 1-2 Skeleton ALLBASE/SQL C Program

.

/* STATIC VARIABLE DECLARATION PART */

sqlca Declaration

sqlda Declaration

.

/* Host Variable Declarations */

/* Host Variables can be global, local, or both */

.

/* main DECLARATION PART */

main(argc,argv)

/* Parameter Declaration */

{

.

/* Host Variable Declarations */

/* Host Variables can be local, or for called routines */



/* C statements, some containing SQL Commands */

EXEC SQL ...



int FunctionName();

.

}

/* FUNCTION DECLARATION PART */

FunctionName(parameter list)

/* Parameter Declaration */

  {

  .

  /* Host Variable Declarations */

  /* Host Variables can be local */



  /* C statements, some containing SQL Commands */

  EXEC SQL ...

  .

  }

Most SQL commands appear within C functions in which you establish DBEnvironment access and manipulate data in a database. Variable declarations should follow rules for coding C programs without SQL statements. In addition to functions for various kinds of database access, you should code a CONNECT function, a RELEASE function, an error handling function, and transaction management functions containing BEGIN WORK and COMMIT WORK statements.

Rules of Syntax for Embedded SQL Statements

You must follow some simple rules when embedding SQL statements in C code:

  • Commands must be of appropriate size:

    • An embedded SQL command has no maximum length.

    • A dynamic SQL command within a host variable is limited only by the size of the host variable's declaration.

    • A dynamic SQL command not within a host variable can be no longer than 2048 bytes.

  • Use EXEC SQL as the prefix to each SQL statement. The entire prefix, EXEC SQL, must appear on one line, as follows:

       EXEC SQL SELECT PartName INTO :PartName
    
            FROM PurchDB.Parts WHERE PartNumber = :PartNumber;
    

    The following is not legal:

       EXEC
    
            SQL SELECT PartName INTO :PartName
    
            FROM PurchDB.Parts WHERE PartNumber = :PartNumber;
    
  • Use a semicolon at the end of the SQL command, as shown above.

  • C comments (those which begin with /*and end with */) may appear within or between embedded SQL commands, as in the following:

       EXEC SQL SELECT PartNumber, PartName
    
            /*put the data into the following host variables  */
    
       INTO :PartNumber, :PartName
    
            /*find the data in the following table */
    
       FROM PurchDB.Parts
    
            /*retrieve only data that satisfies this search condition */
    
       WHERE PartNumber = :PartNumber;
    
            /*end of command */
    
  • SQL comments can be inserted in any line of an SQL statement, except the last line, by prefixing the comment character with at least one space followed by two hyphens followed by one space:

       EXEC SQL SELECT * FROM PurchDB.Parts   -- This code selects Parts Table values
    
                WHERE SalesPrice > 500.;
    

    The comment terminates at the end of the line on which it appears. (The decimal point in the 500 improves performance when being compared to SalesPrice, which also has a decimal; no data type conversion is necessary.)

  • Non-numeric literals in embedded commands may be continued from one line to another.

  • When referring to a host variable within an embedded SQL statement, precede it with a colon (:). Do not use the colon outside the embedded SQL statement.

A sample source file appears at the end of this chapter. And more detailed explanation of coding for different types of embedded SQL statements appears in Chapters 4 through 8.

Preprocessing the Source File

After embedding SQL commands in the source code, preprocess it with the ALLBASE/SQL C preprocessor. Use the following command, which is described fully in Chapter 2:

   :RUN PSQLC.PUB.SYS; INFO="DBEnvironmentName (MODULE (ModuleName))"

In addition to checking the syntax of your SQL statements, preprocessing also does the following:

  • Creates a modified source file.

  • Stores sections in the DBEnvironment.

  • Generates a file, SQLMSG, for preprocessing messages. Creates an installable module file.

Creating the Modified Source File

The preprocessor translates embedded SQL statements into C language statements and comments out the SQL statements. Non-SQL statements in your code are not translated. As output, the preprocessor creates a modified source file which can then be compiled. The original source file is not changed.

The preprocessor also creates three include files, which contain variable declarations, type declarations, and external procedure declarations used by the preprocessor generated C code.

The modified source file contains include statements which direct the compiler to incorporate these include files at compile time.

Creating Stored Sections

The preprocessor also stores runtime instructions in the system catalog of the DBEnvironment you specify when preprocessing. These instructions are called sections and are stored in a module, which contains a section for each DML, DDL, or DCL statement in your program that can be completely defined before run time. A module is referenced in the system catalog of the DBEnvironment.

Not all SQL statements cause the preprocessor to store a section. Only statements that access data cause a section to be stored.

A section has three parts:

  • A stored form of the SQL command.

  • Instructions for executing the command according to the best available access path.

  • A flag indicating whether the section is valid or invalid.

These elements are illustrated in Figure 1-3.

Figure 1-3 Components of a Stored Section

[Components of a Stored Section]
Stored Form of the SQL Command

In addition to translating each SQL statement into C code, the preprocessor stores a version of the statement in a section. This version of the statement is used at a later time if it becomes necessary to revalidate the section.

Optimized Access Instructions

ALLBASE/SQL also chooses the best available path for accessing the data referred to in the statement. This process is called optimization. For example, the following query can be optimized:

   EXEC SQL SELECT * FROM PurchDB.Parts

        WHERE PartNumber = :PartNumber;

ALLBASE/SQL first determines whether or not indexes exist on the PartNumber column. If there are indexes, ALLBASE/SQL then computes whether the use of an available index is more efficient than doing a serial scan of the entire table. The result of this decision whether or not to use the index (or which index to use, if there is more than one) is stored as part of the section for the query.

Validity Flag

The validity flag provides a way to ensure that any objects you reference in an SQL statement still exist and that runtime authorization criteria are satisfied. If the SQL command in a section references objects that exist at preprocessing time and the individual doing the preprocessing is authorized to issue the command, the stored section is marked as valid. If the SQL command references an object that does not exist at preprocessing time or if the individual doing the preprocessing is not authorized to issue the command, the stored section is marked as invalid.

After being stored by the preprocessor, a valid section is marked as invalid when activities such as the following occur:

  • Changes in authorities of the module's owner.

  • Alterations to tables accessed by the program.

  • Deletions or creations of indexes.

  • Updating a table's statistics.

In general, ALLBASE/SQL invalidates a section whenever there is a chance that the existing access path to the data might have changed. Suppose you drop an index on a column that appears in a query. In such a case, the section which contains that query and any other sections which reference that column are marked invalid.

Runtime Revalidation of Sections

At run time, ALLBASE/SQL checks each section for validity before executing it. When a section is found to be invalid, ALLBASE/SQL revalidates it to revalidate it (if possible), then executes it. You may notice a slight delay as the revalidation takes place. If you wish, you can re-preprocess the entire program to revalidate all sections at once, avoiding the delay of runtime revalidation. However, this is not required, since revalidation is done automatically and transparently.

If an invalid section cannot be validated, as when a table reference is invalid because the table owner name has changed, ALLBASE/SQL returns an error indication to the application program. The new owner can validate the section.

Generating the Message File

During preprocessing, messages are written to the file sqlmsg. If preprocessing is successful, the file contains a statement indicating the name of the module stored in the DBEnvironment and the number of sections stored.

Compiling and Linking the Program

Use the C compiler and system linker to create the executable program from the modified source code file and the include files. You can run both the compiler and the linker with the CCXLLK command. Alternatively, you can create object files by using the CCXL command. In this case, you must link objects in a separate step using the link editor. Figure 1-4 shows both techniques.

Figure 1-4 Ways of Compiling and Linking an ALLBASE/SQL C Program

[Ways of Compiling and Linking an ALLBASE/SQL C Program]
CAUTION: When correcting your programs during the compile process, be sure to edit the original source file, not the preprocessor output file. Note that when it encounters an error, the compiler returns line numbers for the modified source file, so you must extrapolate from these to the actual lines in your original source. Edit the original source, re-preprocess, then re-compile and re-link.

Running the Program

Once the preprocessing and compile steps have completed without error, you can run the application.

All the C constructs inserted by the preprocessor and the stored sections automatically handle database operations, including providing the application program with status information after each SQL command is executed. SQL commands that have a stored section are executed if the section is valid at run time or can be validated by ALLBASE/SQL at run time. As your program runs, it executes code that calls each section that was previously stored. If the section is valid, it is then executed to carry out the query or other SQL operation.

If the section cannot be executed for any reason, ALLBASE/SQL returns an error code to the sqlca. Your program can examine this data structure and print out the text of messages that correspond to the error codes sent back by ALLBASE/SQL. Using a standard error handling routine makes debugging the embedded SQL a straightforward process. Refer to Chapter 4, "Runtime Status Checking and the sqlca," for details and examples of incorporating error routines.

NOTE: The error codes returned at run time are not the same as the errors shown in sqlmsg at preprocessing time. Runtime errors include such logical mistakes as issuing a BEGIN WORK when a transaction is already underway, OPENing a cursor that is already open, and so on.

If your program contains the SQLEXPLAIN command, you can display the text of an ALLBASE/SQL error message as an aid to debugging. SQLEXPLAIN obtains warning and error messages from the ALLBASE/SQL message catalog, which must be available at run time. The default message catalog is SQLCT000.PUB.SYS. For native language users, the catalog is SQLCTxxx.PUB.SYS, where xxx is the numerical value for the current language. (See the "Native Language Support" section for information about how to determine the number for the current language.) If this catalog is not available, ALLBASE/SQL issues a warning and then uses the default catalog instead.

Authorizations

ALLBASE/SQL authorization governs who can preprocess, execute, and maintain a program that accesses an ALLBASE/SQL DBEnvironment.

To preprocess a program for the first time, you need CONNECT or DBA authority in the DBEnvironment your program accesses. When you preprocess a program, your login name becomes the owner of that module. Subsequently, only you or someone else with DBA authority can re-preprocess the program.

To access an ALLBASE/SQL DBEnvironment through a program, you need the authority to execute the command used in the program to start the DBE session:

  • If the program uses a CONNECT command to start a DBE session, you need CONNECT authority and RUN or module OWNER authority to run the program.

  • If the program uses a START DBE command to start the DBE session, you need DBA authority to run the program.

At run time, any SQL command in the program is executed only if the original OWNER of the module has the authorization to execute the command at run time. However, any dynamic command (an SQL command entered by the user at run time) is executed only if the login of the user running the program has the authority to execute the entered command.

Whoever runs the program must have either RUN authorization for the module or else be the OWNER or DBA. Granting authorizations is further described in Chapter 2 of this manual and in the ALLBASE/SQL Database Administration Guide.

Debugging and Testing

As you test the program, use a set of database tables that resembles the production DBEnvironment as closely as possible. This will let you judge the performance of the program as well as exercising each of the segments of code. Remember that in debugging and testing the application, you are also testing the DBEnvironment's parameters. Elements such as log size, buffer size, maximum number of transactions, and other configurable parameters may need to be adjusted for the needs of the application. Use SQLUtil to adjust the parameters of the DBEnvironment. (DBA authority is required.)

After testing in single user mode, run tests with multiple users to observe the level of concurrency and the degree of throughput your application achieves. If relevant, observe the performance of the application while other applications are running. Refer to the ALLBASE/SQL Reference Manual for additional guidelines on coding for performance.