INFORMIX
Informix-ESQL/C Programmer's Manual
Chapter 14: Using Dynamic SQL
Home Contents Index Master Index New Book

SQL Statements That Are Known at Compile Time

The simplest type of dynamic SQL to execute is one for which you know both of the following items:

The following sections describe how to execute both non-SELECT statements and SELECT statements whose structure and data are known at compile time.

Executing Non-SELECT Statements

In this chapter, the term non-SELECT statement refers to any SQL statement that can be prepared, except SELECT and EXECUTE FUNCTION. This term includes the EXECUTE PROCEDURE statement.

Important: The INSERT statement is an exception to the rules for non-SELECT statements. If the INSERT inserts a single row, use PREPARE and EXECUTE to execute it. However, if the INSERT is associated with an insert cursor, you must declare the insert cursor. For more information, see "Sending More Than One Row".
For a list of SQL statements that cannot be prepared, see the entry for the PREPARE statement in the Informix Guide to SQL: Syntax.

You can execute a non-SELECT statement in the following ways:

Using PREPARE and EXECUTE

The PREPARE and EXECUTE statements allow you to separate the execution of a non-SELECT statement into two steps:

1. PREPARE sends the statement string to the database server, which parses the statement and assigns it a statement identifier.

    2. EXECUTE executes the prepared statement indicated by a statement identifier.

This two-step process is useful for statements that need to be executed more than once. You reduce the traffic between the client application and the database server when you parse the statement only once.

For example, you can write a general-purpose deletion program that works on any table. This program would take the following steps:

1. Prompt the user for the name of the table and the text of the WHERE clause and put the information into C variables such as tabname and search_condition. The tabname and search_condition variables do not need to be host variables because they do not appear in the actual SQL statement.

    2. Create a text string by concatenating the following four components: DELETE FROM, tabname, WHERE, and search_condition. In this example, the string is in a host variable called stmt_buf: sprintf(stmt_buf, "DELETE FROM %s WHERE %s",
    tabname, search_condition);

    3. Prepare the entire statement. The following PREPARE statement operates on the string in stmt_buf and creates a statement identifier called d_id: EXEC SQL prepare d_id from :stmt_buf;

    4. Execute the statement. The following EXECUTE statement executes the DELETE: EXEC SQL execute d_id;

    5. If you do not need to execute the statement again, free the resources used by the statement identifier structure. This example would use the following FREE statement: EXEC SQL free d_id;

If the non-SELECT statement contains input parameters, you must use the USING clause of the EXECUTE statement. For more information, see "Using an EXECUTE USING Statement".

The EXECUTE statement is generally used to execute non-SELECT statements. You can use EXECUTE with the INTO clause for a SELECT or an EXECUTE FUNCTION statement as long as these statements return only one group of values (one row). For more information, see "Using PREPARE and EXECUTE INTO". However, do not use the EXECUTE statement for:

Using EXECUTE IMMEDIATE

Rather than prepare the statement and then execute it, you can prepare and execute the statement in the same step with the EXECUTE IMMEDIATE statement. The EXECUTE IMMEDIATE statement also frees statement-identifier resources upon completion.

For example, for the DELETE statement used in the previous section, you can replace the PREPARE-EXECUTE statement sequence with the following statement:

You cannot use EXECUTE IMMEDIATE if the statement string contains input parameters. (For information, see "Using an EXECUTE USING Statement".) The SQL statements also have restrictions that you can execute with EXECUTE IMMEDIATE. For a complete list of SQL statement restrictions, see the entry for EXECUTE IMMEDIATE in the Informix Guide to SQL: Syntax.

Executing SELECT Statements

You can execute a SELECT statement in the following two ways:

Using PREPARE and EXECUTE INTO

The only prepared SELECT statement that you can execute with the EXECUTE statement is a singleton SELECT. Your ESQL/C program must take the following actions:

1. Declare host variables to receive the values that the database server returns.

    2. Assemble and prepare the statement.

    3. Execute the prepared selection with the EXECUTE...INTO statement, with the host variables after the INTO keyword.

    If the SELECT statement contains input parameters, include the USING clause of EXECUTE.

Tip: To execute a singleton SELECT, using EXECUTE...INTO is usually more efficient than using the DECLARE, OPEN, and FETCH statements.
With the INTO clause of the EXECUTE statement, you can still use the following features:

    Use the INDICATOR keyword followed by the name of the indicator host variable, as follows:

EXEC SQL prepare sel1 from

'select fname, lname from customer where customer_num = 123';

EXEC SQL execute sel1 into :fname INDICATOR :fname_ind,
:lname INDICATOR :lname_ind;

    Include the USING clause of EXECUTE, as follows:

EXEC SQL prepare sel2 from

'select fname, lname from customer where customer_num = ?';

EXEC SQL execute sel2 into :fname, :lname using :cust_num;

Warning: When you use the EXECUTE INTO statement, make sure that the SELECT statement is a singleton SELECT. If the SELECT returns more than one row, you receive a runtime error. An error is also generated if you attempt to execute a prepared statement that has been declared (with DECLARE).
You are not required to prepare a singleton SELECT. If you do not need the benefits of a prepared statement, you can embed a singleton SELECT statement directly in your ESQL/C program, as shown in the following example:

Figure 14-8 shows how to execute the items_pct() SPL function (which Figure 16-3 shows). Because this function returns a single decimal value, the EXECUTE...INTO statement can execute it.

Figure 14-8
Executing the items_pct SPL Function

You can use host variables for routine arguments but not the routine name. For example, if the manu_code variable holds the value "HSK", the following EXECUTE statement replaces the input parameter in the prepared statement to perform the same task as the EXECUTE in Figure 14-8.

If you do not know the number or data types of the select-list columns or function return values, you must use a dynamic-management structure instead of host variables with the EXECUTE...INTO statement. The dynamic-management structure defines the select-list columns at runtime. For more information, see "Handling an Unknown Select List".

Using a Select Cursor

To execute a SELECT statement that returns more than one row, you must declare a select cursor. The select cursor enables the ESQL/C application to handle multiple rows that a query returns.

Your ESQL/C program must take the following actions to use a select cursor:

1. Declare host variables to receive the values that the database server returns.

    2. Assemble and prepare the statement.

    3. Declare the select cursor.

    The DECLARE statement associates the prepared SELECT statement with the select cursor.

    4. Execute the query.

    The OPEN statement sends any input parameters that its USING clause specifies to the database server and tells the database server to execute the SELECT statement.

    5. Retrieve the rows of values from the select cursor.

    The FETCH statement retrieves one row of data that matches the query criteria.

For more information on cursors and cursor-management statements, see "Using a Database Cursor".

Warning: Do not use the INTO clause in both a SELECT statement that is associated with a cursor and in a FETCH statement that retrieves data from the cursor. Neither the ESQL/C preprocessor nor the executable program generate an error for this condition. Using the INTO clause in both statements, however, can generate unexpected results.

Executing User-Defined Routines in Universal Server

In Universal Server, a user-defined routine is a collection of statements that performs a user-defined task. A procedure is a routine that can accept arguments but does not return any values. A function is a routine that can accept arguments and returns values. The following table summarizes the SQL statements for user-defined routines.

Task SQL Statement for User Defined Routines

Procedure Function

Create and register a routine

CREATE PROCEDURE

CREATE FUNCTION

Execute a routine

EXECUTE PROCEDURE

EXECUTE FUNCTION

Drop a routine

DROP PROCEDURE

DROP FUNCTION

For more information on these statements, see the Informix Guide to SQL: Syntax.

Universal Server supports several languages for user-defined routines:

Tip: In earlier versions of Informix products, the term "stored procedure" was used for both SPL procedures and SPL functions. That is, a stored procedure could include the RETURN statement to return values. For backward compatibility with earlier products, Universal Server continues to support the execution of SPL functions with the EXECUTE PROCEDURE statement. However, for new SPL routines, Informix recommends that you use EXECUTE PROCEDURE only for procedures and EXECUTE FUNCTION only for functions.
A user-defined routine can use input parameters for its arguments. However, it cannot use an input parameter for its routine name. For more information, see "Executing Statements with Input Parameters".

A User-Defined Procedure

If you know the name of the user-defined procedure (external or SPL) at compile time, execute the user-defined procedure with the EXECUTE PROCEDURE statement. The following EXECUTE PROCEDURE statement executes a user-defined procedure called revise_stats():

For more information on the syntax of the EXECUTE PROCEDURE statement, see the Informix Guide to SQL: Syntax.

If you do not know the name of the user-defined procedure until runtime, you must dynamically execute the procedure. To dynamically execute a user-defined procedure, you can use:

A User-Defined Function

If you know the name of the user-defined function at compile time, execute the user-defined function (external or SPL) with the EXECUTE FUNCTION statement. In the INTO clause of EXECUTE FUNCTION, you list the host variables that hold the return value(s). The following EXECUTE FUNCTION statement executes a user-defined function called items_pct() (which Figure 16-3 defines):

For more information on the syntax of the EXECUTE FUNCTION statement, see the Informix Guide to SQL: Syntax.

If you do not know the name of the user-defined function until runtime, you must dynamically execute the function. Dynamic execution of a user-defined function is a similar dynamic execution of a SELECT statement (page 15-24). Both the SELECT and the user-defined function return values to the ESQL/C program.

Execute a user-defined function with the EXECUTE FUNCTION statement. You can execute an EXECUTE FUNCTION statement in the following two ways:

    This type of user-defined function is often called a cursor function. A cursor function that is written in SPL (an SPL function) has the WITH RESUME clause in its RETURN statement. A cursor function that is written in an external language such as C is an iterator function.

Tip: If you do not know the data type of the return value, you must use a dynamic-management structure to hold the value. For more information, see page 15-27.

A Noncursor Function
You can also use the PREPARE and EXECUTE statement to execute a noncursor user-defined function. A noncursor function returns only one row of values.

Your ESQL/C program must take the following actions:

1. Declare host variables to receive the values that the database server returns.

    2. Assemble and prepare the statement.

    3. Execute the prepared user-defined function with the EXECUTE...INTO statement, with the host variables after the INTO keyword.

    If the EXECUTE FUNCTION contains input parameters, include the USING clause of EXECUTE.

Important: To execute a noncursor function, EXECUTE...INTO is usually more efficient than the DECLARE, OPEN, and FETCH statements. However, you often do not know the number of returned rows. When you do not use a cursor to execute a cursor function that returns multiple rows, ESQL/C generates a runtime error. Therefore, it is a good practice to always associate a user-defined function with a cursor. For more information, see page 14-50.
EXT
Most external functions can return only one row of data and only a single value. For example, the following code fragment executes an external function called stnd_dev():

To return more than one value, the external function must return a complex data type, such as a collection or a row type. (For more information on these data types, see Chapter 9, "Working with INFORMIX-Universal Server Complex Data Types.")

SPL
An SPL function can return one or more values. If the RETURN statement of the SPL function does not contain the WITH RESUME keywords, then the function returns only one row. To execute the SPL function dynamically, prepare the EXECUTE FUNCTION and execute it with the EXECUTE...INTO statement.

For more information, see "Using PREPARE and EXECUTE INTO".

A Cursor Function
To execute an EXECUTE FUNCTION statement whose user-defined function returns more than one row, you must declare a function cursor. The function cursor enables the ESQL/C application to handle the multiple rows that a user-defined function returns. Your ESQL/C program must take the following actions to use a function cursor:

1. Declare host variables to receive the values that the user-defined function returns.

    2. Assemble and prepare the statement.

    3. Declare the function cursor.

    The DECLARE statement associates the prepared EXECUTE FUNCTION statement with the function cursor.

    4. Execute the user-defined function.

    The OPEN statement sends any input parameters that its USING clause specifies to the database server and tells the database server to execute the EXECUTE FUNCTION statement.

    5. Retrieve the rows of values from the function cursor.

    The FETCH statement retrieves one row of values that the user-defined function returns.

EXT
Only an external function that is an iterator function can return more than one row of data. For information on how to write an iterator function, see the
DataBlade API Programmer's Manual.

SPL
If the RETURN statement of the SPL function contains the WITH RESUME keywords, then the function can return more than one row. You must associate such an SPL function with a function cursor. To execute the SPL function dynamically, associate the EXECUTE FUNCTION statement with a cursor, use the OPEN statement to execute the function, and use the FETCH...INTO statement to retrieve the rows from the cursor into host variables.

For more information on cursors and cursor-management statements, see "Using a Database Cursor".

Executing Statements with Input Parameters

An input parameter is a placeholder in an SQL statement that indicates that the actual value will be provided at runtime. You cannot list a host-variable name in the text of a dynamic SQL statement because the database server knows nothing about variables declared in the application. Instead, you can indicate an input parameter with a question mark (?), which serves as a placeholder, anywhere within a statement where an expression is valid. You cannot use an input parameter to represent an identifier such as a database name, a table name, or a column name.

An SQL statement that contains input parameters is called a parameterized statement. For a parameterized SQL statement, your program must provide the following information to the database server about its input parameters:

    The first input parameter is defined for the value of the customer_num column and the second for the value of the order_date column.

The statement that you use to provide an input parameter with a value at runtime depends on the type of SQL statement that you execute, as follows:

When the statement executes, you can list host variables or literal values to substitute for each input parameter in the USING clause. The values must be compatible in number and data type with the associated input parameters. A host variable must also be large enough to hold the data.

Important: To use host variables with the USING clause, you must know the number of parameters in the SQL statement and their data types. If you do not know the number and data types of the input parameters at runtime, you must use a dynamic-management structure with the USING clause. For more information, see "Determining Unknown Input Parameters".
The following sections show how to use host variables with the OPEN...USING and the EXECUTE...USING statements.

Using an EXECUTE USING Statement

You can execute a parameterized non-SELECT statement (a non-SELECT that contains input parameters) with the EXECUTE...USING statement. The following statements are parameterized non-SELECT statements:

Tip: You cannot use an input parameter as the procedure name for a user-defined procedure.
For example, the following UPDATE statement requires two parameters in its WHERE clause:

The USING clause lists the names of the host variables that hold the parameter data. If the input parameter values are stored in hvar1 and hvar2, your program can execute this UPDATE with the following statement:

The following steps describe how to handle a parameterized UPDATE or DELETE statement when the type and number of parameters are known at compile time:

1. Declare a host variable for each input parameter that is in the prepared statement.

    2. Assemble the character string for the statement, with a question mark (?) placeholder for each input parameter. Once you have assembled the string, prepare it. For more information on these steps, see "Assembling and Preparing the SQL Statement".

    3. Assign a value to the host variable that is associated with each input parameter. (The application might obtain these values interactively.)

    4. Execute the UPDATE or DELETE statement with the EXECUTE...USING statement. You must list the host variables that contain the input parameter values in the USING clause.

    5. Optionally, use the FREE statement to release the resources that were allocated with the prepared statement.

Important: If you do not know the number and data types of the input parameters in the prepared statement at compile time, do not use host variables with the USING clause. Instead, use a dynamic-management structure to specify input parameter values. For more information, see "Determining Unknown Input Parameters".
For more information on the USING clause, see the entry for EXECUTE in the Informix Guide to SQL: Syntax.

Using an OPEN USING Statement

You can execute the following statements with the OPEN...USING statement:

Tip: You cannot use an input parameter as the function name for a user-defined function.
For example, the following SELECT statement is a parameterized SELECT that requires two parameters in its WHERE clause:

If the cust_num and ord_date host variables contain the input parameter values, the following OPEN statement executes the SELECT with these input parameters:

Use the USING host_var clause only when you know, at compile time, the type and number of input parameters in the WHERE clause of the SELECT statement. For more information on the USING clause, see the entry for OPEN in the Informix Guide to SQL: Syntax.

The demo2.ec sample program shows how to handle a dynamic SELECT statement that has input parameters in its WHERE clause. The demo2.ec program uses a host variable to hold the value of the input parameter for a SELECT statement. It also uses host variables to hold the column values that are returned from the database.

1 #include <stdio.h>

2 EXEC SQL define FNAME_LEN 15;

3 EXEC SQL define LNAME_LEN 15;


	4	 main()

5 {

6 EXEC SQL BEGIN DECLARE SECTION;

7 char demoquery[80];

8 char queryvalue[2];

9 char fname[ FNAME_LEN + 1 ];

10 char lname[ LNAME_LEN + 1 ];

11 EXEC SQL END DECLARE SECTION;

12 printf("DEMO2 Sample ESQL program running.\n\n");

13 EXEC SQL connect to'stores7';

14 /* The next three lines have hard-wired the query. This

15 * information could have been entered from the terminal

16 * and placed into the demoquery string

17 */

18 sprintf(demoquery, "%s %s",

19 "select fname, lname from customer",

20 "where lname > ? ");

21 EXEC SQL prepare demo2id from :demoquery;

Lines 9 and 10
These lines declare a host variable (fname) for the parameter in the WHERE clause of the SELECT statement and declare host variables (fname and lname) for values that the SELECT statement returns.

Lines 14 to 21
These lines assemble the character string for the statement (in demoquery) and prepare it as the demo2id statement identifier. The question mark (?) indicates the input parameter in the WHERE clause. For more information on these steps, see "Assembling and Preparing the SQL Statement".

22 EXEC SQL declare demo2cursor cursor for demo2id;

23 /* The next line has hard-wired the value for the parameter.

24 * This information could also have been entered from the terminal

25 * and placed into the queryvalue string.

26 */

27 sprintf(queryvalue, "C");

28 EXEC SQL open demo2cursor using :queryvalue;


	29	 	for (;;)

30 {

31 EXEC SQL fetch demo2cursor into :fname, :lname;

32 if (strncmp(SQLSTATE, "00", 2) != 0)

33 break;

34 /* Print out the returned values */

35 printf("Column: fname\tValue: %s\n", fname);

36 printf("Column: lname\tValue: %s\n", lname);

37 printf("\n");

38 }

Line 22
This line declares the demo2cursor cursor for the prepared statement identifier, demo2id. All nonsingleton SELECT statements must have a declared cursor.

Lines 23 to 27
The queryvalue host variable is the input parameter for the SELECT statement. It contains the value "C". In an interactive application, this value probably would be obtained from the user.

Line 28
The database server executes the SELECT statement when it opens the demo2cursor cursor. Because the WHERE clause of the SELECT statement contains input parameters (lines 20 and 21), the OPEN statement includes the USING clause to specify the input parameter value in queryvalue.

Lines 29 to 38
This for loop executes for each row fetched from the database. The FETCH statement (line 31) includes the INTO clause to specify the fname and lname host variables for the column values. After this FETCH statement executes, the column values are stored in these host variables.

39 if (strncmp(SQLSTATE, "02", 2) != 0)

40 printf("SQLSTATE after fetch is %s\n", SQLSTATE);

41 EXEC SQL close demo2cursor;


	42	 	EXEC SQL free demo2cursor;

43 EXEC SQL free demo2id;

44 EXEC SQL disconnect current;

45 printf("\nProgram Over.\n");

46 }

Lines 39 and 40
Outside the for loop, the program tests the SQLSTATE variable again so it can notify the user in the event of successful execution, a runtime error, or a warning (class code not equal to "02").

Line 41
After all the rows are fetched, the CLOSE statement closes the demo2cursor cursor.

Lines 42 and 43
These FREE statements release the resources allocated for the prepared statement (line 42) and the database cursor (line 43). Once a cursor or prepared statement has been freed, it cannot be used again in the program.




Informix-ESQL/C Programmer's Manual, version 9.1
Copyright © 1998, Informix Software, Inc. All rights reserved.