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.
DataBlade API Function | Step in Prepared-Statement Execution |
---|---|
mi_prepare( ) | Prepares a text representation of the SQL statement to execute |
mi_statement_command_name( ), mi_get_statement_row_desc( ), or input-parameter accessor function (Table 57) | Obtains information about the prepared statement |
mi_exec_prepared_statement( ) or mi_open_prepared_statement( ) | Sends the prepared statement to the database server for execution |
mi_drop_prepared_statement( ) | Releases prepared-statement resources |
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:
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:
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 34 prepares an unparameterized SELECT statement that obtains column values from the customer table.
stmt_desc = mi_prepare(conn, "SELECT * FROM customer;", NULL)
For more information, see Assembling a Statement String.
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 35 shows an INSERT statement that uses input parameters as placeholders for two column values in the customer table.
insrt_stdesc = mi_prepare(conn, "INSERT INTO customer (customer_num, company) \ VALUES (?,?);", NULL
In Figure 35, 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.
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 a name as the third argument of the mi_prepare( ) function.
The last argument to mi_prepare( ) specifies the cursor name for the prepared statement. Assigning a cursor 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:
WHERE CURRENT OF cursor_name
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:
SELECT customer_num, company FROM customer WHERE customer_num = 104 FOR UPDATE OF company; SELECT customer_num, company FROM customer WHERE customer_num = 104;
For more information on the FOR UPDATE keywords of SELECT with databases that are ANSI compliant and not ANSI compliant, see Defining a Cursor Mode.
The following code fragment uses the mi_prepare( ) statement to assign a name to a cursor and an UPDATE WHERE CURRENT OF statement to update the fifth row in this cursor:
/* Prepare the FOR UPDATE statement */ if ( (stmt1 = mi_prepare(conn, "select * from tab1 for update;", "curs1")) == NULL ) return MI_ERROR; /* Open the cursor */ if ( mi_open_prepared_statement(stmt1, MI_BINARY, MI_QUERY_BINARY, num_params, values, lengths, nulls, types, NULL, 0, NULL) != MI_OK ) return MI_ERROR; /* Fetch the 5th row */ if ( mi_fetch_statement(stmt1, MI_CURSOR_NEXT, 0, 5) != MI_OK ) return MI_ERROR; /* Get values from 5th row */ if ( mi_get_result(conn) != MI_ROWS || mi_next_row(conn, &res) == NULL ) return MI_ERROR; /* Update 5th row */ if ( mi_exec("update tab1 set int_col = int_col + 2 \ where current of curs1;", NULL) != MI_OK ) return MI_ERROR; /* Clean up */ if ( mi_close_statement(stmt1) != MI_OK ) return MI_ERROR; if ( mi_drop_prepared_statement(stmt1) != MI_OK ) return MI_ERROR;
The mi_open_prepared_statement( ) function also provides the ability to name the cursor. However, if you specify a cursor name in mi_prepare( ), make sure that you pass a NULL-valued pointer as the cursor name to mi_open_prepared_statement( ). Conversely, if you want to specify the cursor name in mi_open_prepared_statement( ), use a NULL-valued pointer as the cursor name in mi_prepare( ). If you specify a cursor name in both mi_prepare( ) and mi_open_prepared_statement( ), the DataBlade API uses the cursor name that mi_open_prepared_statement( ) provides.
If your prepared statement does not fetch rows, pass a NULL-valued pointer as the third argument to mi_prepare( ).
The last argument to mi_prepare( ) specifies the statement name for the prepared statement. The cursor_name argument of mi_open_prepared_statement( ) specifies the cursor name for the prepared statement. If you do not need to assign a statement name, pass a NULL-valued pointer as the last argument to mi_prepare( ).
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 an explicit statement descriptor (usually called just 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.
Memory Duration | Memory Operation | Function Name |
---|---|---|
Not allocated from memory-duration pools | Constructor | mi_prepare( ) |
Destructor | mi_drop_prepared_statement( ),
mi_close_statement( ) |
A statement descriptor can be identified in either of the following ways:
The mi_prepare( ) function is a constructor function for a statement descriptor.
Table 56 lists the DataBlade API accessor functions for an explicit 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 (Table 57) |
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 to obtain information about a particular column (see Table 22). |
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( ).
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. Table 57 lists the DataBlade API accessor functions that obtain input-parameter information from the statement descriptor.
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 Table 57 raise an exception.
The statement descriptor stores input-parameter information in several parallel arrays.
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 Table 57.
Figure 36 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.
To access information for the nth input parameter, provide an index value of n-1 to the appropriate accessor function in Table 57. 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:
MI_STATEMENT *stmt_desc; MI_TYPEID *param_type; mi_integer param_nullable; ... param_type = mi_parameter_type_id(stmt_desc, 1); param_nullable = mi_parameter_nullable(stmt_desc, 1);
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.
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 perform one of the following tasks:
|
Both these functions support the following parameters.
Parameter | Description |
---|---|
stmt_desc | Is 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 | Is the number of input-parameter values in the input-parameter-value arrays |
Input-parameter-value arrays:
|
Arrays that contain the following information
for each input-parameter 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.
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( ).
DataBlade API Function | Step in Prepared-Statement Execution |
---|---|
mi_prepare( ) | Prepares the statement string for execution |
mi_statement_command_name( ), mi_get_statement_row_desc( ), or input-parameter accessor function (Table 57) | Obtains information about the prepared statement (optional) |
mi_exec_prepared_statement( ) | Sends the prepared statement to the database server for execution and opens any cursor required |
mi_drop_prepared_statement( ) | Releases prepared-statement resources |
The mi_exec_prepared_statement( ) function performs the following tasks for the prepared SQL statement:
For more information, see Assigning Values to Input Parameters.
The control flag supports the MI_BINARY flag to indicate that query rows are to be returned in binary representation. For more information, see Determining Control Mode for Query Data.
The DataBlade API stores the cursor as part of the statement descriptor. For more information on this row cursor, see Queries and Implicit Cursors.
When the mi_exec_prepared_statement( ) function successfully fetches the query rows into the cursor, the cursor position points to the first row of the cursor, and the mi_get_result( ) function returns a status of MI_ROWS to indicate that the cursor contains rows.
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 Example: The send_statement( ) Function) uses mi_exec_prepared_statement( ) instead of mi_exec( ) to send an SQL statement to the database server:
mi_integer send_statement2(conn, stmt) MI_CONNECTION *conn; mi_string *stmt; { mi_integer count; MI_STATEMENT *stmt_desc; /* Prepare the statement */ if ( (stmt_desc = mi_prepare(conn, stmt, NULL)) == NULL ) mi_db_error_raise(conn, MI_EXCEPTION, "mi_prepared failed\n"); /* Send the basic statement, specifying that query * be sent in its text representation */ if ( mi_exec_prepared_statement(stmt_desc, 0, MI_FALSE, 0, NULL, NULL, NULL, 0, NULL) == MI_ERROR ) mi_db_error_raise(conn, MI_EXCEPTION, "mi_exec_prepared_statement failed\n"); /* Get the results of the current statement */ count = get_results(conn); /* Release statement resources */ if ( mi_drop_prepared_statement(stmt_desc) == MI_ERROR ) mi_db_error_raise(conn, MI_EXCEPTION, "mi_drop_prepared_statement failed\n"); if ( mi_query_finish(conn) == MI_ERROR ) mi_db_error_raise(conn, MI_EXCEPTION, "mi_query_finish failed\n"); return ( count ); }
The mi_exec_prepared_statement( ) function allocates type descriptors for each of the data types of the input parameters. If the calls to mi_exec_prepared_statement( ) are in a loop in which these data types do not vary between loop iterations, mi_exec_prepared_statement( ) can reuse the type descriptors, as follows:
This method saves on the number of type descriptors that mi_exec_prepared_statement( ) must allocate, thereby reducing memory usage.
In Figure 37, mi_exec_prepared_statement( ) in the initial pass of the for loop specifies the INTEGER data type for the single input parameter in an INSERT statement. For subsequent passes of the for loop, mi_exec_prepared_statement( ) receives a NULL-valued pointer for its types array. When it receives this NULL-valued pointer, mi_exec_prepared_statement( ) reuses the type descriptor that it has already created.
mi_string *types[1] = {"int"}; mi_string **types_exec; ... sprintf(command, "insert into tabA values(?, %d);", j); if ( (stmt_desc = mi_prepare(conn, command, NULL)) == NULL ) { return -1; } types_exec = types; for (j=0; j < numLoop; j++) { values[0] = (MI_DATUM) j; if ( (ret = mi_exec_prepared_statement(stmt_desc, MI_BINARY, 1, 1, values, lengths, nulls, types_exec, 0, NULL)) ) { return -2; } if ( (ret = mi_get_result(conn)) == MI_ERROR ) return -4; if ( ret == MI_DML || MI_DDL ) row_count += mi_result_row_count(conn); types_exec = NULL; /* reuse data types from 1st pass */ }
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( ).
DataBlade API Function | Step in Execution of Prepared Statement |
---|---|
mi_prepare( ) | Prepares the statement string for execution |
mi_statement_command_name( ), mi_get_statement_row_desc( ), or input-parameter accessor function (Table 57) | Obtains information about the prepared statement (optional) |
mi_open_prepared_statement( ) | Sends the prepared statement to the database server for execution and open the cursor |
mi_fetch_statement( ) | Retrieves any data that the query returns |
mi_close_statement( ), mi_drop_prepared_statement( ) | Releases prepared-statement resources |
The mi_open_prepared_statement( ) function performs the following tasks for the prepared SQL statement:
For more information on how to assign input-parameter values, see Assigning Values to Input Parameters.
The DataBlade API stores the cursor as part of the statement descriptor. For more information on this cursor, see Defining an Explicit Cursor.
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:
The cursor_name parameter is a pointer to the string name that you want to assign to the cursor. You can use this cursor_name for an update cursor so that the UPDATE or DELETE statement can reference the cursor in its clause:
WHERE CURRENT OF cursor_name
For more information, see Assigning an Optional Name.
To use an internally-generated unique name for the cursor, specify a NULL-valued pointer for the cursor_name argument.
The mi_open_prepared_statement( ) function supports several flag values in its control flag that determine the type of cursor it creates. For more information, see Defining an Explicit Cursor.
In addition, the control flag also supports the MI_BINARY flag to indicate that query rows are to be returned in binary representation. For more information, see Determining Control Mode for Query Data.
Unlike mi_exec( ) and mi_exec_prepared_statement( ), mi_open_prepared_statement( ) does not read any retrieved rows into the open cursor. To fetch rows into the explicit cursor, use the mi_fetch_statement( ) function. For more information, see Fetching Rows Into a Cursor.
The mi_open_prepared_statement( ) function allocates type descriptors for each of the data types of the input parameters. If the calls to mi_open_prepared_statement( ) are in a loop in which these data types do not vary between loop iterations, mi_open_prepared_statement( ) can reuse the type descriptors, as follows:
This method saves on the number of type descriptors that mi_open_prepared_statement( ) must allocate, thereby reducing memory usage. For sample code in which the mi_exec_prepared_statement( ) function reuses type descriptors, see Figure 37.
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:
The mi_open_prepared_statement( ) function supports the following types of cursors for holding query rows.
You can pass only once through the rows.
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. 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, but if the data in the database changes, the data in the cursor does not reflect these changes.
Table 58 shows the control-flag values that determine cursor type and cursor mode.
You can specify one of the following cursor modes for the cursor with the control-flag bit mask.
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 ANSI-compliant, as follows:
You do not need to specify the FOR READ ONLY keywords in the SELECT statement. The only advantage of specifying the FOR READ ONLY keywords explicitly is for better program documentation. To specify an update mode, you must specify the FOR UPDATE keywords in the SELECT statement.
You do not need to specify the FOR UPDATE keywords in the SELECT statement. The only advantage of specifying the FOR UPDATE keywords explicitly is for better program documentation. To specify a read-only mode, you must specify the FOR READ ONLY keywords in the SELECT statement.
For more information on the FOR UPDATE and FOR READ ONLY clauses, see the description of the SELECT statement in the IBM Informix: Guide to SQL Syntax.
By default, both the sequential and scroll cursor types have a cursor mode of update (also called read/write). Table 58 shows the cursor types and cursor modes, with the required bit-mask values for the control flag.
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.
When mi_open_prepared_statement( ) successfully opens a cursor, the cursor is empty, with the cursor position pointing to the first location of the cursor, and the mi_get_result( ) function returns a status of MI_NO_MORE_RESULTS to indicate that the cursor does not contain rows.
Figure 38 shows the state of the explicit cursor that contains one integer column after mi_open_prepared_statement( ) executes.
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, the following items are true:
With mi_fetch_statement( ), you can request rows at different locations based on the type of cursor that mi_open_prepared_statement( ) has defined. To specify location, mi_fetch_statement( ) has an action argument of type MI_CURSOR_ACTION, which supports the cursor-action constants in the following table.
Figure 39 shows the state of a row cursor that Figure 38 defines after the following mi_fetch_statement( ) executes:
mi_fetch_statement(stmt_desc, MI_CURSOR_NEXT, 0, 0);
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:
You can obtain the number of query rows with the mi_result_row_count( ) function.
The mi_fetch_statement( ) for Figure 39 specified a value of zero (0) as the number of rows to fetch, which tells the function to fetch all retrieved rows. Figure 40 shows the state of the row cursor that Figure 38 defines when the mi_fetch_statement( ) function specifies a num_rows argument of three instead of zero, as follows:
mi_fetch_statement(stmt_desc, MI_CURSOR_NEXT, 0, 3);
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:
mi_string *cmd = "select order_num from orders \ where customer_num = ?;"; MI_STATEMENT *stmt; ... if ( (stmt = mi_prepare(conn, cmd, NULL)) == NULL ) mi_db_error_raise(NULL, MI_EXCEPTION, "mi_prepare( ) failed"); values[0] = 104; types[0] = "integer"; lengths[0] = 0; nulls[0] = MI_FALSE; /* Open the read-only cursor to hold the query rows */ if ( mi_open_prepared_statement(stmt, MI_SEND_READ, MI_TRUE, 1, values, lengths, nulls, types, "cust_select", retlen, rettypes) != MI_OK ) mi_db_error_raise(NULL, MI_EXCEPTION, "mi_open_prepared_statement( ) failed"); /* Fetch the retrieved rows into the cursor */ if ( mi_fetch_statement(stmt, MI_CURSOR_NEXT, 0, 3) != MI_OK ) mi_db_error_raise(NULL, MI_EXCEPTION, "mi_fetch_statement( ) failed"); if ( mi_get_result(conn) != MI_ROWS ) mi_db_error_raise(NULL, MI_EXCEPTION, "mi_get_result( ) failed or found nonquery statement"); /* Retrieve the query rows from the cursor */ if ( !(get_data(conn)) ) mi_db_error_raise(NULL, MI_EXCEPTION, "get_data( ) failed"); /* Close the cursor */ if ( mi_close_statement(stmt) == MI_ERROR ) mi_db_error_raise(NULL, MI_EXCEPTION, "mi_close_statement( ) failed"); /* Release resources */ if ( mi_drop_prepared_statement(stmt) == MI_ERROR ) mi_db_error_raise(NULL, MI_EXCEPTION, "mi_drop_prepared_statement( ) failed"); if ( mi_close(conn) == MI_ERROR ) mi_db_error_raise(NULL, MI_EXCEPTION, "mi_close( ) failed");
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.
For a parameterized SQL statement, your DataBlade API module must perform the following steps:
The mi_prepare( ) statement performs these first two steps for a parameterized statement. For more information, see Preparing an 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 36). They have an element for each input parameter in the prepared statement. However, they are unlike the input-parameter arrays in the statement descriptor in the following ways:
An input-parameter array describes the column with which the input parameter is associated.
The DataBlade API does not provide accessor functions for input-parameter value arrays. For each input parameter, your DataBlade API module must declare, allocate, and assign a value to the array.
All of the input-parameter-value arrays have zero-based indexes. Figure 41 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.
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.
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 structure that holds the value for each input parameter. The format of this value depends on:
The params_are_binary argument of mi_exec_prepared_statement( ) or mi_open_prepared_statement( ) indicates this control mode. For more information on the format of data for different control modes, see Table 55.
For more information, see Contents of an MI_DATUM Structure.
For the prepared INSERT statement in Figure 35, the code fragment in Figure 42 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.
/* Initialize input parameter for customer_num column */ values[0] = "0"; /* value of '0' for SERIAL customer_num */ lengths[0] = 0; /* SERIAL is built-in type: no length */ types[0] = "serial"; nulls[0] = MI_FALSE; /* Initialize input parameter for company column */ stcopy("Trievers Inc.", strng); values[1] = strng; lengths[1] = stleng(strng); /* CHAR types need length! */ types[1] = "char(20)"; nulls[1] = MI_FALSE; /* Send INSERT statement to database server for execution along * with the input-parameter-value arrays */ mi_exec_prepared_statement(insrt_stdesc, 0, MI_FALSE, 2 values, lengths, nulls, types, 0, NULL);
The following code fragment initializes the input parameters to the same values but it assigns these values in binary representation instead of text representation:
/* Initialize input parameter for customer_num column */ values[0] = 0; /* value of 0 for SERIAL customer_num */ lengths[0] = 0; /* SERIAL is built-in type: no length */ types[0] = "serial"; nulls[0] = MI_FALSE; /* Initialize input parameter for company column */ values[1] = mi_string_to_lvarchar("Trievers Inc."); lengths[1] = 0; /* CHAR types need length! */ types[1] = "char(20)"; nulls[1] = MI_FALSE; /* Send INSERT statement to database server for execution along * with the input-parameter-value arrays */ mi_exec_prepared_statement(insrt_stdesc, 0, MI_TRUE, 2 values, lengths, nulls, types, 0, NULL);
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 structure of this array must be passed by value.
In a client LIBMI application, all values in MI_DATUM structure 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:
col1 = 0; values[0] = &col1;
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:
Make sure the lengths value matches the length of the null-terminated string of the input-parameter value (minus the null terminator). Use a library function, such as strlen( ) or stleng( ), to determine the string length.
Lengths are not needed in the following special cases:
A varying-length structure holds its own data length.
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:
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.
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.
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:
mi_open_prepared_statement(stmt_desc, MI_BINARY, ...);
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:
mi_open_prepared_statement( stmt_desc, MI_BINARY + MI_SEND_SCROLL, ...);
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.
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 |
---|---|
Explicit cursor | mi_close_statement( ) |
Statement descriptor (including any cursor) | mi_drop_prepared_statement( ) |
For prepared queries (SQL statements that return rows), the statement descriptor has a cursor associated with it. The scope of this cursor is from the time it is opened, with mi_exec_prepared_statement( ) or mi_open_prepared_statement( ), until one of the following events occurs:
To conserve resources, use the mi_close_statement( ) function to explicitly close an explicit cursor once your DataBlade API module no longer needs it. The mi_close_statement( ) function is the destructor function for an explicit cursor that is associated with a statement descriptor. That is, it frees the 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( ).
The mi_close_statement( ) function is not the destructor function for an implicit cursor that is associated with a statement descriptor. That is, it does not free the cursor that the mi_exec_prepared_statement( ) function opens. To close an implicit cursor, use the mi_drop_prepared_statement( ) function.
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 (such as an implicit or explicit cursor) 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.
Enterprise Edition Home | Express Edition Home | [ Top of Page | Previous Page | Next Page | Contents | Index ]