informix
Informix DataBlade API Programmer's Manual
Executing SQL Statements

Executing SQL Statements

To execute an SQL statement, a DataBlade API module must send the SQL statement to the database server, where the statement is actually executed. The DataBlade API provides the following statement-execution functions for use in a DataBlade API module:

All of these functions perform the same basic task: they send a string representation of an SQL statement to the database server, which executes it and returns statement results. The mi_exec() function is the simplest way to execute an SQL statement.

This section provides a summary of factors to consider when choosing the DataBlade API statement-execution function to use. It then describes the two methods for statement execution.

Method of Statement Execution For More Information
Parse, optimize, and execute the statement in one step Executing Basic SQL Statements
Parse and optimize the statement to create a prepared statement Execute the prepared statement Executing Prepared SQL Statements

Tip: Before you use a DataBlade API function that sends an SQL statement to the database server, make sure you obtain a valid connection descriptor.

Choosing the DataBlade API Function

Figure 8-1 shows the functions that the DataBlade API provides to send SQL statements to the database server for execution.

Figure 8-1
Statement-Execution Functions of the DataBlade API

DataBlade API Function When to Use Function
Statement Type Statement Executed Many Times or Contains Input Parameters? Query Can Use Implicit Cursor?
mi_exec() Query, Other valid SQL statements No Yes
mi_exec_prepared_statement() Query, Other valid SQL statements Yes Yes
mi_open_prepared_statement() Query only Yes No

As the preceding table shows, you need to consider the following factors when deciding which DataBlade API statement-execution function to use:

Choose the DataBlade API statement-execution function that is appropriate for the needs of your DataBlade API application.

Statement Type

The DataBlade API statement-execution functions can execute the following statement types:

The following table shows how to choose a DataBlade API statement-execution function based on SQL statement type.

Statement Type DataBlade API Function
Query,
Other valid statements
mi_exec(),
mi_exec_prepared_statement()
Query only mi_open_prepared_statement()

Prepared Statements and Input Parameters

A prepared SQL statement is the parsed version of an SQL statement. The database server prepares an SQL statement for execution at a later time. Preparing a statement allows you to separate the parsing and execution phases of the statement execution. When you prepare a statement, you send the statement to the database server to be parsed. The database server checks the statement for syntax errors and creates an optimized version of the statement for execution.

Therefore, you only need to prepare an SQL statement once. You can then execute the statement multiple times. Each time you execute the statement you avoid the parsing phase. Prepared statements are useful for SQL statements that execute often in your DataBlade API module.

SQL statements that have missing column or expression values are called parameterized statements because you use input parameters as placeholders for missing column values or expressions. An input parameter is a placeholder in an SQL statement that indicates that the actual column value is provided at runtime. You can specify input parameters in the statement text representation of an SQL statement for the following reasons:

For a parameterized SQL statement, your DataBlade API module must provide the following information to the database server for each of its input parameters.

Input-Parameter Information For More Information
Specify the input parameter in the text of the SQL statement Assembling a Prepared Statement
Specify the value for the input parameter when the statement executes. Assigning Values to Input Parameters

You can also obtain information about the input parameters once the parameterized statement is prepared. For more information, see Obtaining Input-Parameter Information.

Therefore, a DataBlade API module must prepare an SQL statement for the following reasons:

The following table shows how to choose a DataBlade API statement-execution function based on whether the SQL statement needs to be prepared.

Statement Needs to be Prepared? DataBlade API Function
No mi_exec()
Yes mi_exec_prepared_statement(),
mi_open_prepared_statement()

The mi_exec_prepared_statement() and mi_open_prepared_statement() functions provide argument values for specifying the input-parameter values when they execute the statement. You can also use these functions to execute prepared statements that do not have input parameters.

Queries and Implicit Cursors

When a DataBlade API statement-execution function executes a query, it must create a place to hold the resulting rows. Therefore, each of these functions automatically creates a row cursor (often called simply a cursor). The row cursor is an area of memory that serves as a holding place for rows that the database server has retrieved.

The simplest way to hold the rows of a query is to use an implicit cursor, which is defined with the following characteristics.

Cursor Characteristic Restriction
Read-only You can only examine the contents of the row cursor. You cannot modify these contents.
Sequential A sequential cursor allows movement through the rows of the cursor in the forward direction only. You cannot go backward through the cursor. To reaccess a row that you have already accessed, you must close the cursor, reopen it, and move to the desired row.

Most DataBlade API modules can use an implicit cursor for accessing rows. However, if the cursor characteristics of the implicit cursor are not adequate for the needs of your DataBlade API module, you can define an explicit cursor with any of the following cursor characteristics.

Cursor Characteristic Description
Cursor type Which direction does the cursor allow you to access rows?
You can choose a sequential cursor or a scroll cursor.
Cursor mode Which operations are valid on the rows in the cursor?
You can choose read-only or update mode.
Cursor lifespan How long does the cursor remain open?
You can choose whether to use a hold cursor.

For more information on these cursor characteristics, see Defining an Explicit Cursor.

The following table shows how to choose a DataBlade API statement-execution function based on the type of cursor that the query requires.

Can Query Use Implicit Cursor? DataBlade API Function
Yes mi_exec(),
mi_exec_prepared_statement()
No mi_open_prepared_statement()

With the mi_open_prepared_statement() function, you can specify an explicit cursor to hold the query rows. In addition, you can assign a name to the cursor that you can use in other SQL statements.

Executing Basic SQL Statements

The mi_exec() function provides the simplest way to send a basic SQL statement to the database server for execution. A basic SQL statement is one that does not need to be prepared. That is, the statement does not execute many times in the DataBlade API module or it does not contain input parameters. To send a basic SQL statement to the database server for execution, take the following steps:

The database server parses the statement string, optimizes it, executes it, and sends back the statement results.

Assembling the Statement String

The mi_exec() function passes the SQL statement to the database server as a statement string, which is a text representation of the SQL statement. To execute a statement with mi_exec(), the statement string must include the entire SQL statement; that is, it cannot contain any input parameters.

You can assemble this statement string in the following ways:

The statement string can contain multiple SQL statements. Each SQL statement must be terminated with the semicolon (;) symbol. For more information, see Executing Multiple SQL Statements.

Sending the SQL Statement

The mi_exec() function is for the execution of basic SQL statements, both queries and other valid SQL statements. In a DataBlade API module, use the following DataBlade API functions to execute a basic SQL statement.

Step in Execution of Basic SQL Statement DataBlade API Function
Send the basic SQL statement to the database server for execution and open any cursor required. mi_exec()
Release statement resources. mi_query_finish(), mi_query_interrupt()

Once the database server executes the statement, it sends back the statement results, including whether the statement was successful and any query data. After mi_exec() executes, the SQL statement it sent is the most recent SQL statement on the connection. This most recent SQL statement is called the current statement. Only one statement per connection is current. The mi_exec() function creates an implicit statement descriptor to hold the information about the current statement. You obtain the status of the current statement with the mi_get_result() function. For more information, see Processing Statement Results.

Tip: The return value that the mi_exec() function returns does not indicate the success of the current statement. It indicates if mi_exec() was able to successfully send the statement to the database server.

When mi_exec() executes a query, it performs the following additional steps:

The Implicit Row Cursor

When mi_exec() executes a query, it automatically opens an implicit cursor to hold the resulting rows. This cursor is associated with the current statement and is stored as part of the connection descriptor. Therefore, only one cursor per connection can be current. For more information, see Queries and Implicit Cursors.

Tip: If the implicit cursor that mi_exec() creates does not adequately meet the needs of your DataBlade API module, you can use the mi_open_prepared_statement() function to define other types of cursors. For more information, see Defining an Explicit Cursor.

When the mi_exec() function successfully fetches the query results into the cursor:

You can access these rows one at a time with the mi_next_row() function. Each access obtains the row to which the cursor position points. After each access to the cursor, the cursor position moves to the next row. For more information, see Retrieving Query Data.

Control Modes for Query Data

The data that the database server returns for a query can be in one of two control modes:

Figure 8-4 shows the format of different data types in the two control modes.

Figure 8-4
Control Modes for Data

Kind of Data Text Representation Binary Representation
Character Null-terminated string Varying-length structure: mi_lvarchar
Date "mm/dd/yyyy" Nondefault locale: End-user date format Integer number of days since December 31, 1899 (DATE, mi_date)
Date/time "yyyy-mm-dd HH:MM:SS" Nondefault locale: End-user date and time format dtime_t (DATETIME, mi_datetime)
Interval "yyyy-mm" "dd HH:MM:SS" Nondefault locale: End-user date and time format intrvl_t (INTERVAL, mi_interval)
Integer Integer value as a string: thousands separator = "," Nondefault locale: End-user numeric format Internal format:
  • 2-byte integer
    (SMALLINT, mi_smallint)
  • 4-byte integer
    (INTEGER, mi_integer)
  • 8-byte integer: ifx_int8_t
    (INT8, mi_int8)
  • Decimal Fixed-point value as a string: thousands separator = ","
    decimal separator = "."
    Nondefault locale: End-user numeric format
    dec_t (DECIMAL, mi_decimal)
    Monetary Fixed-point value as a string: thousands separator = ","
    decimal separator = "."
    currency symbol = "$"
    Nondefault locale: End-user monetary format
    dec_t (MONEY, mi_money)
    Floating-point Floating-point value as a string: thousands separator = ","
    decimal separator = "."
    Nondefault locale: End-user numeric format
    Internal format:
  • single-precision floating point (SMALLFLOAT, mi_real)
  • double-precision floating point (FLOAT, mi_double_precision)
  • Boolean "t" or "T" "f" or "F" MI_TRUE, MI_FALSE (BOOLEAN, mi_boolean)
    Smart large object Text representation of the LO handle
    (obtained with mi_lo_to_string())
    LO handle (CLOB, BLOB; MI_LO_HANDLE)
    Row type Unnamed row type:
    "ROW(fld_value1, fld_value2, ...)"
    Named row type:
    "row_type(fld_value1, fld_value2, ...)"
    Row structure (ROW, named row type; MI_ROW)
    Collection type "SET{elmnt_value, elmnt_value, ...}" "MULTISET{elmnt_value, elmnt_value, ...}" "LIST{elmnt_value, elmnt_value, ...}" Collection structure (SET, LIST, MULTISET; MI_COLLECTION)
    Varying-length opaque type External format of opaque type
    (as returned by output support function)
    Varying-length structure: mi_lvarchar
    Fixed-length opaque type External format of opaque type
    (as returned by output support function)
    Internal C data type
    Distinct type Text representation of its source data type Binary representation of its source data type

    The mi_exec() function indicates the control mode of the query with a bit-mask control argument, which is one of the following flags.

    Control Mode Control-Flag Value
    Text representation MI_QUERY_NORMAL
    Binary representation MI_QUERY_BINARY

    In the send_statement() function (page 8-15), mi_exec() sets the control mode of the query data to text representation.

    To determine the control mode for query data, use the mi_binary_query() function. The mi_binary_query() function determines the control mode for data of the current statement.

    Example: send_statement() Function

    The send_statement() function takes an existing open connection and an SQL statement string as arguments and sends the statement to the database server with the mi_exec() function. It specifies text representation for the query results.

    The send_statement() function calls another user function, get_results(), to examine the status of the current statement. For the implementation of the get_results() function, see Example: get_results() Function.

    Executing Prepared SQL Statements

    A prepared statement is an SQL statement that is parsed and ready for execution. For these statements, you prepare the statement once and execute it as many times as needed. The DataBlade API provides the following functions to execute a prepared SQL statement.

    Step in Prepared-Statement Execution DataBlade API Function
    Prepare a text representation of the SQL statement to execute mi_prepare()
    Obtain information about the prepared statement See list of functions in Figure 8-7 on page 8-20
    Send the prepared statement to the database server for execution mi_exec_prepared_statement(), mi_open_prepared_statement()
    Release prepared-statement resources mi_drop_prepared_statement()

    Preparing the SQL Statement

    To turn a statement string for an SQL statement into a format that the database server can execute, use the mi_prepare() statement. The mi_prepare() function performs the following tasks to create a prepared statement:

    Assembling a Prepared Statement

    The mi_prepare() function passes the SQL statement to the database server as a statement string. For the mi_prepare() function, a statement string can contain either of the following formats of an SQL statement:

    Assembling Unparameterized Statements

    If you know all the statement information before the statement is prepared, you assemble an unparameterized statement as the statement string. Pass the SQL statement as a string (or a variable that contains a string) to the mi_prepare() function. For example, Figure 8-5 prepares an unparameterized SELECT statement that obtains column values from the customer table.

    Figure 8-5
    Preparing an Unparameterized Statement

    For more information, see Assembling the Statement String.

    Assembling Parameterized Statements

    If some column or expression value is provided when the statement actually executes, you assemble the parameterized statement as the statement string. Specify input parameters in the statement text representation of an SQL statement. For a description of an input parameter, see Prepared Statements and Input Parameters.

    You indicate the presence of an input parameter with a question mark (?) anywhere within a statement where an expression is valid. You cannot list a program-variable name in the text of an SQL statement because the database server knows nothing about variables declared in the DataBlade API module. You cannot use an input parameter to represent an identifier such as a database name, a table name, or a column name.

    For example, Figure 8-6 shows an INSERT statement that uses input parameters as placeholders for two column values in the customer table.

    Figure 8-6
    Preparing an INSERT that Contains Input Parameters

    In Figure 8-6, the first input parameter is defined for the value of the customer_num column and the second for the value of the company column.

    Before the prepared statement executes, your DataBlade API module must assign a value to the input parameter. You pass these input-parameter values as arguments to the mi_exec_prepared_statement() or mi_open_prepared_statement() function. For more information, see Assigning Values to Input Parameters.

    Assigning an Optional Statement Name

    You can obtain access to a prepared statement through its statement descriptor. However, other SQL statements that need to reference the prepared statement cannot use a statement descriptor. Therefore, you can assign an optional string name to a prepared SQL statement. Specify the desired statement name as the third argument of the mi_prepare() function. The statement name that you assign with mi_prepare() also applies to any cursor that the prepared statement might use.

    Assigning a statement name is useful for a statement that includes an update cursor so that an UPDATE or DELETE statement that contains the following clause can reference the cursor in this clause:

    You can specify an update cursor in the syntax of the SELECT statement that you prepare, as the following versions of the SELECT statement show:

    For more information on the FOR UPDATE keywords of SELECT with databases that are ANSI compliant and not ANSI compliant, see Defining Cursor Mode.

    The mi_open_prepared_statement() function also provides the ability to name the cursor. However, if you specify a statement name in mi_prepare(), make sure that you pass a NULL-valued pointer as the cursor name to mi_open_prepared_statement(). Generally, statements are named with mi_prepare().

    If you do not need to assign a statement name, pass a NULL-valued pointer as the last argument to mi_prepare().

    Returning a Statement Descriptor

    The mi_prepare() function sends the contents of an SQL statement string to the database server, which parses the statement and returns it in an optimized executable format. The function returns a pointer to a statement descriptor. A statement descriptor, MI_STATEMENT, is a DataBlade API structure that contains the information about a prepared SQL statement, including the executable format of the SQL statement.

    The following table summarizes the memory operations for a statement descriptor.

    Default Memory Duration Memory Operation Function Name
    Not allocated from memory-duration pools Constructor mi_prepare()
    Destructor mi_drop_prepared_statement(), mi_close()

    A statement descriptor can be identified in either of the following ways:

    Figure 8-7 lists the DataBlade API accessor functions for a statement descriptor.

    Figure 8-7
    Accessor Functions for a Statement Descriptor

    Statement-Descriptor Information DataBlade API Accessor Function
    The name of the SQL statement that was prepared mi_statement_command_name()
    Information about any input parameters in the prepared statement The input-parameter accessor functions
    (
    Figure 8-8 on page 8-21)
    A row descriptor for the columns in the prepared statement mi_get_statement_row_desc() From the row descriptor, you can use the row-descriptor accessor functions (see Figure 5-11 on page 5-24) to obtain information about a particular column.

    Important: To DataBlade API modules, the statement descriptor (MI_STATEMENT) is an opaque C structure. Do not access the internal fields of this structure directly. Informix does not guarantee that the internal structure of the MI_STATEMENT will not change in future releases. Therefore, to create portable code, always use these accessor functions to obtain prepared-statement information.

    You pass a statement descriptor to the other DataBlade API functions that handle prepared statements, including mi_exec_prepared_statement(), mi_open_prepared_statement(), mi_fetch_statement(), mi_close_statement(), and mi_drop_prepared_statement().

    Tip: The DataBlade API also provides several private functions that use statement descriptors. These private functions are only available to DataBlade partners for special DataBlade functionality. For more information on private statement-descriptor functions, see your Informix sales representative.

    Obtaining Input-Parameter Information

    From a statement descriptor, you can obtain information about an input parameter once an SQL statement has been prepared. An input parameter indicates a value that is provided when the prepared statement executes. Figure 8-8 lists the DataBlade API accessor functions that obtain input-parameter information from the statement descriptor.

    Figure 8-8
    Input-Parameter Information in the Statement Descriptor

    Column Information DataBlade API
    Accessor Function
    The number of input parameters in the prepared statement mi_parameter_count()
    The precision (total number of digits) of the column associated with an input parameter mi_parameter_precision()
    The scale of a column that is associated with the input parameter mi_parameter_scale()
    Whether the column associated with each input parameter was defined with the NOT NULL constraint mi_parameter_nullable()
    The type identifier of the column that is associated with the input parameter mi_parameter_type_id()
    The type name of the column that is associated with the input parameter mi_parameter_type_name()

    Important: To DataBlade API modules, the input-parameter information in the statement descriptor (MI_STATEMENT) is part of an opaque C data structure. Do not access the internal fields of this structure directly. Informix does not guarantee that the internal structure of the MI_STATEMENT structure will not change in future releases. Therefore, to create portable code, always use these accessor functions to obtain input-parameter information.

    Input-parameter information is available only for the INSERT and UPDATE statements. Support for the UPDATE statement includes the following forms of UPDATE:

    If you attempt to request input-parameter information for other SQL statements, the input-parameter functions in Figure 8-8 raise an exception.

    The statement descriptor stores input-parameter information in several parallel arrays.

    Input-Parameter Array Contents
    Parameter-type ID array Each element is a pointer to a type identifier (MI_TYPEID) that indicates the data type of the input parameter.
    Parameter-type name array Each element is a pointer to the string name of the data type for each input parameter.
    Parameter-scale array Each element is the scale of the column associated with the input parameter.
    Parameter-precision array Each element is the precision of the column associated with the input parameter.
    Parameter-nullable array Each element is either:
  • MI_FALSE: the input parameter is associated with a column that cannot contain SQL NULL values
  • MI_TRUE: the input parameter is associated with a column that can contain SQL NULL values
  • All of the input-parameter arrays in the statement descriptor have zero-based indexes. Within the statement descriptor, each input parameter in the prepared statement has a parameter identifier, which is the zero-based position of the input parameter within the input-parameter arrays. When you need information about an input parameter, specify its parameter identifier to one of the statement-descriptor accessor functions in Figure 8-8 on page 8-21.

    Figure 8-9 shows how the information at index position 1 of these arrays holds the input-parameter information for the second input parameter of a prepared statement.

    Figure 8-9
    Input-Parameter Arrays in the Statement Descriptor

    To access information for the nth input parameter, provide an index value of n-1 to the appropriate accessor function in Figure 8-8 on page 8-21. The following calls to the mi_parameter_type_id() and mi_parameter_nullable() functions obtain from the statement descriptor that stmt_desc identifies the type identifier (param_type) and whether the column is nullable (param_nullable) for the second input parameter:

    To obtain the number of input parameters in the prepared statement (which is also the number of elements in the input-parameter arrays), use the mi_parameter_count() function.

    Sending the Prepared Statement

    For a prepared statement to be executed, you must send it to the database server with one of the following DataBlade API functions.

    DataBlade API Function When To Use
    mi_exec_prepared_statement()
  • If the prepared statement does not return rows
  • If the prepared statement does return rows but you only need to access these rows sequentially (with an implicit cursor)
  • mi_open_prepared_statement()
  • If the prepared statement does return rows and you need to:
  • Both these functions support the following parameters.

    Parameter Description
    stmt_desc A pointer to a statement descriptor for the prepared statement The mi_prepare() function generates this statement descriptor.
    control flag Determines whether any query rows are in binary or text representation
    params_are_binary Indicates whether the input-parameter values are in binary or text representation
    n_params The number of input-parameter values in the input-parameter-value arrays
    Input-parameter-value arrays:
  • values
  • types
  • lengths
  • nulls
  • Arrays that contain the following information for each input-parameter value:
  • Value
  • Data type
  • Length (for varying-length data types)
  • Whether the input-parameter value is an SQL NULL value For more information, see Assigning Values to Input Parameters.
  • retlen The number of column values that are in each retrieved row
    rettypes An array that contains the data types of any returned column values

    Once the database server executes the prepared statement, the statement becomes the current statement. The database server sends back the statement results, including whether the current statement was successful. Obtain the status of the current statement with the mi_get_result() function. For more information, see Processing Statement Results.

    Statements with mi_exec_prepared_statement()

    The mi_exec_prepared_statement() function is for the execution of prepared statements, both queries and other valid SQL statements. In a DataBlade API module, use the following DataBlade API functions to execute a prepared SQL statement with mi_exec_prepared_statement().

    Step in Prepared-Statement Execution DataBlade API Function
    Prepare the statement string for execution. mi_prepare()
    Obtain information about the prepared statement (optional). See list of functions in Figure 8-7 on page 8-20
    Send the prepared statement to the database server for execution and open any cursor required. mi_exec_prepared_statement()
    Release prepared-statement resources. mi_drop_prepared_statement()

    The mi_exec_prepared_statement() function performs the following tasks for the prepared SQL statement:

    When the mi_exec_prepared_statement() function successfully fetches the query rows into the cursor:

    You can access these rows one at a time with the mi_next_row() function. Each access obtains the row to which the cursor position points. After each access to the cursor, the cursor position moves to the next row. For more information, see Retrieving Query Data.

    The following variation of the send_statement() function (page 8-15) uses mi_exec_prepared_statement() instead of mi_exec() to send an SQL statement to the database server:

    Statements with mi_open_prepared_statement()

    The mi_open_prepared_statement() function is for the execution of queries. In a DataBlade API module, use the following DataBlade API functions to execute a prepared SQL statement with mi_open_prepared_statement().

    Step in Execution of Prepared Statement DataBlade API Function
    Prepare the statement string for execution. mi_prepare()
    Obtain information about the prepared statement (optional). See list of functions in Figure 8-7 on page 8-20
    Send the prepared statement to the database server for execution and open the cursor. mi_open_prepared_statement()
    Retrieve any data that the query returns. mi_fetch_statement()
    Release prepared-statement resources. mi_close_statement(), mi_drop_prepared_statement()

    The mi_open_prepared_statement() function performs the following tasks for the prepared SQL statement:

    The main difference between mi_exec_prepared_statement() and mi_open_prepared_statement() is that the latter allows more flexibility in the definition of the cursor used for the query rows. With mi_open_prepared_statement(), you can define an explicit cursor. In particular, mi_open_prepared_statement() allows you to specify:

    Defining an Explicit Cursor

    The control flag of mi_open_prepared_statement() allows you to define an explicit cursor to hold the rows that the prepared query returns. You can choose the following cursor characteristics when you define the cursor:

    Defining Cursor Type

    The mi_open_prepared_statement() function supports the following types of cursors for holding query rows.

    Cursor Type Description
    Sequential cursor Allows you to move through the rows of the cursor in the forward direction only. Therefore, you can only pass once through the rows.
    Scroll cursor Allows you to move through the rows of the cursor in the forward and backward directions. Therefore, you can move back in the rows without having to reopen the cursor. However, the database server stores the data for a scroll cursor in a temporary table. Therefore, the data can become stale; that is, the data in the cursor is consistent with the data in the database when the cursor is filled. If the data in the database changes, the data in the cursor does not reflect these changes.

    Figure 8-10 shows the control-flag values that determine cursor type and cursor mode.

    Defining Cursor Mode

    You can specify one of the following cursor modes for the cursor with the control-flag bit mask.

    Cursor Mode Description SELECT Statement
    Update Allows you to read and modify the data within the cursor SELECT...FOR UPDATE
    Read-only Allows you to read the data within the cursor; does not allow you to update or delete any row it fetches SELECT...FOR READ ONLY

    When you execute a prepared SELECT statement with no FOR UPDATE or FOR READ ONLY clause, the cursor mode you need depends on whether your database is an ANSI-compliant database, as follows:

    For more information on the FOR UPDATE and FOR READ ONLY clauses, see the description of the SELECT statement in the Informix Guide to SQL: Syntax.

    By default, both the sequential and scroll cursor types have a cursor mode of update (also called read/write). Figure 8-10 shows the cursor types and cursor modes, with the required bit-mask values for the control flag.

    Figure 8-10
    Control-Flag Values for Cursor Type and Mode

    Cursor Control-Flag Value
    Update sequential cursor None (default)
    Read-only sequential cursor MI_SEND_READ
    Update scroll cursor MI_SEND_SCROLL
    Read-only scroll cursor MI_SEND_READ + MI_SEND_SCROLL

    Defining Cursor Lifespan

    You can define the lifespan of the cursor with the control-flag bit mask. By default, the database server closes all cursors at the end of a transaction. If your DataBlade API module requires uninterrupted access to a set of rows across transaction boundaries, you can define a hold cursor. A hold cursor can be either a sequential or a scroll cursor.

    To define a hold cursor, you specify the MI_SEND_HOLD constant in the control-flag bit mask of the mi_open_prepared_statement() function, as the following table shows.

    Cursor Control-Flag Value
    Update sequential cursor with hold MI_SEND_HOLD
    Read-only sequential cursor with hold MI_SEND_READ + MI_SEND_HOLD
    Update scroll cursor with hold MI_SEND_SCROLL + MI_SEND_HOLD
    Read-only scroll cursor with hold MI_SEND_READ + MI_SEND_SCROLL + MI_SEND_HOLD

    Fetching Rows Into a Cursor

    When mi_open_prepared_statement() successfully opens a cursor:

    Figure 8-11 shows the state of the explicit cursor that contains one integer column after mi_open_prepared_statement() executes.

    Figure 8-11
    Row Cursor After mi_open_prepared_statement()

    To populate the open cursor, use the mi_fetch_statement() function, which fetches the specified number of retrieved rows from the database server into the cursor. You can perform a fetch operation on an update or a read-only cursor. To fetch rows into a cursor, you must specify the following information to mi_fetch_statement():

    The mi_fetch_statement() function requests the specified number of retrieved rows from the database server and copies them into the cursor, which is associated with the specified statement descriptor. When mi_fetch_statement() completes successfully:

    With mi_fetch_statement(), you can request rows at different locations based on the type of cursor that mi_open_prepared_statement() has defined.

    Cursor-Action Flag Description Type of Cursor
    MI_CURSOR_NEXT Fetch the next num_rows rows, starting at the current retrieved row on the database server. Sequential, Scroll
    MI_CURSOR_PRIOR Fetch the previous num_rows rows, starting at the current retrieved row. Scroll
    MI_CURSOR_FIRST Fetch the first num_rows rows. Sequential, Scroll
    MI_CURSOR_LAST Fetch the last num_rows rows. Sequential, Scroll
    MI_CURSOR_ABSOLUTE Move jump rows into the retrieved rows and fetch num_rows rows. Sequential (as long as the jump argument does not move the cursor position backward) Scroll
    MI_CURSOR_RELATIVE Move jump rows from the current retrieved row and fetch num_rows rows. Sequential (as long as the jump argument is a positive number) Scroll

    Figure 8-12 shows the state of a row cursor that Figure 8-11 on page 8-33 defines after the following mi_fetch_statement() executes:

    
    

    Figure 8-12
    Fetching All Retrieved Rows Into a Cursor

    Once the rows reside in the cursor, your DataBlade API module can access these rows one at a time with the mi_next_row() function. For more information, see Retrieving Query Data.

    If you specify a non-zero value for the num_rows argument, mi_fetch_statement() fetches the requested number of rows into the cursor. Specify a non-zero value for num_rows if your DataBlade API module needs to handle rows in smaller groups. In this case, you retrieve num_rows number of query rows from the cursor with mi_next_row(). When mi_next_row() indicates that no more rows are in the cursor, you must determine whether to fetch any remaining rows from the database server into the cursor, as follows:

    The mi_fetch_statement() for Figure 8-12 on page 8-35 specified a value of zero (0) as the number of rows to fetch, which tells the function to fetch all retrieved rows. Figure 8-13 shows the state of the row cursor that Figure 8-11 on page 8-33 defines when the mi_fetch_statement() function specifies a num_rows argument of three instead of zero:

    The following code fragment uses the mi_open_prepared_statement() function to assign an input-parameter value, execute a SELECT statement, and retrieve the query rows:

    This code fragment sends its input-parameter value in binary representation. The code fragment is part of a C UDR because it passes the INTEGER input-parameter value by value. For more information, see Assigning Values to Input Parameters.

    Assigning Values to Input Parameters

    For a parameterized SQL statement, your DataBlade API module must perform the following steps:

    1. Specify input parameters in the text of the SQL statement.
    2. Send the SQL statement to the database server for parsing.
    3. Provide input-parameter values when the SQL statement executes.

    The mi_prepare() statement performs these first two steps for a parameterized statement. For more information, see Preparing the SQL Statement.

    The mi_exec_prepared_statement() and mi_open_prepared_statement() functions assign values to input parameters when they send a parameterized SQL to the database server for execution. To provide a value for an input parameter, you pass information in several parallel arrays:

    These input-parameter value arrays are similar to the input-parameter arrays in the statement descriptor (see Figure 8-9 on page 8-23). They have an element for each input parameter in the prepared statement. However, unlike the input-parameter arrays in the statement descriptor:

    All of the input-parameter-value arrays have zero-based indexes. Figure 8-14 shows how the information at index position 1 of these arrays holds the input-parameter-value information for the second input parameter of a prepared statement.

    Figure 8-14
    Arrays for Initialization of Input Parameters

    You specify the number of input-parameter values in the input-parameter value arrays with the nparams argument of mi_exec_prepared_statement() or mi_open_prepared_statement().

    The following sections provide additional information about each of the input-parameter-value arrays.

    Parameter-Value Array

    The parameter-value array, values, is the fifth argument of the mi_exec_prepared_statement() and mi_open_prepared_statement() functions. Each element of the parameter-value array is a pointer to an MI_DATUM that holds the value for each input parameter. The format of this value depends on:

    For the prepared INSERT statement in Figure 8-6 on page 8-18, the code fragment in Figure 8-15 assigns values to the input parameters for the customer_num and company columns. These values are in text representation because the params_are_binary argument of mi_exec_prepared_statement() is MI_FALSE.

    Figure 8-15
    Executing an INSERT that Contains Text-Representation Input Parameters

    The following code fragment initializes the input parameters to the same values but it assigns these values in binary representation instead of text representation:

    In the preceding code fragment, the first element of the values array is assigned an integer value. Because this code executes in a C UDR, the integer value in the MI_DATUM of this array must be passed by value.

    In a client LIBMI application, all values in MI_DATUM must be passed by reference. Therefore, to assign values to input parameters within a client LIBMI application, you must assign all values in the values array as pointers to the actual values.

    The preceding code fragment assumes that it executes within a C UDR because it passes the value for the first input parameter (an INTEGER column by value. In a client LIBMI application, you cannot use the pass-by-value mechanism. Therefore, the assignment to the first input parameter must pass a pointer to the integer value, as follows:

    Parameter-Value Length Array

    The parameter-value length array, lengths, is the sixth argument of the mi_exec_prepared_statement() and mi_open_prepared_statement() functions. Each element of the parameter-value length array is the integer length (in bytes) of the data type for the input-parameter value.

    The meaning of the values in the lengths array depends on the control mode of the input-parameter values, as follows:

    Parameter-Value Null Array

    The parameter-value null array, nulls, is the seventh argument of the mi_exec_prepared_statement() and mi_open_prepared_statement() functions. Each element of the parameter-value null array is either:

    Parameter-Value Type Array

    The parameter-value type array, types, is the eighth argument of the mi_exec_prepared_statement() and mi_open_prepared_statement() functions. Each element of the parameter-value type array is a pointer to a string that identifies the data type of the input-parameter value. The type names must match those that the mi_type_typename() function would generate for the data type.

    If the prepared statement has input parameters and is not an INSERT statement, you must use the types array to supply the data types of the input parameters. Otherwise, you can pass in a NULL-valued pointer as the types argument.

    Determining Control Mode for Query Data

    The mi_exec_prepared_statement() and mi_open_prepared_statement() functions specify the control mode for the data of a prepared query in their bit-mask control argument. To determine the control mode, set the control argument as the following table shows.

    Control Mode Control Argument
    Text representation Zero (default)
    Binary representation MI_BINARY

    For mi_exec_prepared_statement(), MI_BINARY is the only valid control-flag constant for the control argument. Therefore, a default value of zero (0) as the control argument indicates text representation of the data. The following mi_exec_prepared_statement() call specifies a control mode of binary representation:

    For mi_open_prepared_statement(), the control argument indicates the cursor characteristics in addition to the control mode. To specify a text representation, omit the MI_BINARY control-flag constant from the control argument. Including MI_BINARY in the control argument indicates that results are to be returned in binary representation. The following mi_open_prepared_statement() call specifies an update scroll cursor and a control mode of binary representation:

    For information on how to specify cursor characteristics to mi_open_prepared_statement(), see Defining an Explicit Cursor. For more information on the control mode, see Control Modes for Query Data.

    Releasing Prepared-Statement Resources

    When your DataBlade API module no longer needs a prepared statement, you can release the resources that it uses with the following DataBlade API functions.

    Prepared-Statement Resource DataBlade API Function
    Cursor mi_close_statement()
    Statement descriptor (including the cursor) mi_drop_prepared_statement()

    Closing a Statement Cursor

    For prepared queries (SQL statements that return rows), the statement descriptor has a cursor associated with it. This cursor has as its scope from the time it is opened with mi_exec_prepared_statement() or mi_open_prepared_statement() until whichever of the following events occurs first:

    To conserve resources, use the mi_close_statement() function to explicitly close the cursor once your DataBlade API module no longer needs it. The mi_close_statement() function is the destructor function for a cursor that is associated with a statement descriptor. That is, it frees the implicit cursor that the mi_exec_prepared_statement() opens or the explicit cursor that the mi_open_prepared_statement() function opens. Until you drop the prepared statement with mi_drop_prepared_statement(), you can still reopen an explicit cursor with another call to mi_open_prepared_statement().

    Tip: The mi_close_statement() function performs the same basic task for a DataBlade API module as the SQL statement CLOSE statement does for an Informix ESQL/C application. Dropping a Prepared Statement

    A statement descriptor describes a prepared statement. However, this DataBlade API structure is not allocated from the memory-duration pools. Instead, its scope is from the time it is created with mi_prepare() until whichever of the following events occurs first:

    To conserve resources, use the mi_drop_prepared_statement() function to explicitly deallocate the statement descriptor once your DataBlade API module no longer needs it. The mi_drop_prepared_statement() function is the destructor function for a statement descriptor. It frees the statement descriptor and any resources that are associated with the statement descriptor. These resources include the prepared statement and any associated row cursor. Once you drop a prepared statement, you must reprepare it before it can be executed again.

    Executing Multiple SQL Statements

    A DataBlade API statement-execution function can send more than one SQL statement to the database server at a time. In this case, the statement string contains several SQL statements, each separated by a semicolon (;). When the statement string contains more than one SQL statement, the mi_get_result() function executes for each statement in the string.

    Suppose you send the following statement string for execution:

    For the preceding statement string, the mi_get_result() function executes four times, three times returning an MI_DML status for each INSERT statement and once to return the final MI_NO_MORE_RESULTS status. For more information on mi_get_result(), see Processing Statement Results.

    Keep in mind that the effects of one part of the statement string are not visible to other parts. Therefore, if one SQL statement depends on an earlier one, do not put them both in the same statement string. For example, the following statement string causes an error:

    The preceding mi_exec() call generates an error occurs because the INSERT statement cannot see the result of the CREATE TABLE statement. The solution is to call mi_exec() twice, as follows:


    Informix DataBlade API Programmer's Manual, Version 9.2
    Copyright © 1999, Informix Software, Inc. All rights reserved