OUT and INOUT parameter support for stored procedure calls in Informix ODBC Driver

A new feature for CSDK ODBC Driver

Learn how the implementation of the OUT and INOUT parameter support in IBM® Informix® ODBC Driver enhances the power of stored procedure calls in Informix. Learn how to employ various types of parameters as OUT or INOUT to send or retrieve data from an Informix database using procedure calls. Although the OUT and INOUT types are the standard parameter types, prior to the CSDK 3.50.xC4 release, the ODBC driver was not supporting these parameter types.

Kollol Kumar Misra (kolmisra@in.ibm.com), Senior Staff Software Engineer, IBM

Photo of author Kollol MisraKollol Kumar Misra works at IBM India Lab, Bangalore. Kollol has more than seven years of IT experience. In his current role, Kollol is lead engineer for IBM Informix CSDK (Client Software Development Kit) at India Software Lab.



Sheshnarayan Agrawal (shagrawal@in.ibm.com), Software Architect, IBM

Shesh Agrawal photoSheshnaraya Agrawal (Shesh) works at IBM India Lab, Bangalore. Shesh has more than 13 years of IT experience. In his current role, Shesh is lead engineer for IBM Optim's distributed product at India Software Lab. Shesh is "Patent Plateau" holder in IBM. Shesh holds Masters Degree in Computer Science. Prior to the Optim responsibility, Shesh worked on IBM Informix CSDK (Client Software Development Kit) development for more than 8 years. Shesh has presented on various topics on Optim and Informix at various national and international conferences such as IOD Las Vegas, IIUG Lenexa, and Software Universe.



31 May 2012

Also available in Russian

Introduction

Database-stored procedures are sets of pre-compiled SQL statements created in the server, and called and executed by database applications. A procedure can exist with or without a return value and with or without parameters. There are three options for parameterized stored procedures:

  1. OUT parameter— You can only receive values from the procedure. Your cannot pass values to OUT parameters in a stored procedure call. After successful execution of the stored procedure, all the OUT parameters values will be assigned to their respective bound variables.
  2. IN parameter— You can only send values to the stored procedure. In the stored procedure body, you can execute queries based on input value. This is the default parameter, and keyword IN is optional.
  3. INOUT parameter— You can send and receive values from the procedure. This provides the benefits of both OUT and IN parameters using the single bound variable.

NOTE: If a parameter type is not explicitly defined, by default it is treated as an IN parameter type.

Starting with CSDK 3.50xC4 release, Informix CSDK-ODBC Driver implemented OUT and INOUT parameter support for stored procedures. Earlier, the CSDK ODBC Driver only supported the IN parameter, and users would receive errors if they attempted to send OUT or INOUT parameter types in a stored procedure. In this article, you'll learn how to implement this new support in your own Informix stored procedures. Sample C code snippets for CSDK-ODBC illustrate the implementation.

In general, there are two types of SQL queries in ODBC applications:

  • SQL queries that only need to execute once with no need to pass or bind parameter values at runtime.
  • SQL queries that need to be executed multiple times with different sets of data. This type is prepared only once (for performance optimization) and executed multiple times with different sets of bound data.

As this article deals with the OUT and INOUT parameters, using prepared statements is the only method you may use to bind variables with the OUT and INOUT parameters of the procedure. The example shown below illustrates executing an SQL query without preparing it.

Listing 1. Executing the statements
rc = SQLExecDirectW (hstmt, L"execute procedure testproc ()", SQL_NTS );

A prepared statement is complied and optimized once and can be used multiple times by setting different parameter values. To execute the same statement many times, using a prepared statement is better. Because it is stored in compiled form, it requires less execution time. The benefit is that the prepared statement not only contains an SQL statement but a pre-compiled SQL statement.

Listing 2. Preparing and executing the statements
rc = SQLExecDirectW (hstmt, L"execute procedure testproc(?)" , SQL_NTS ); 
rc = SQLBindParameter(hstmt,1, SQL_PARAM_INPUT, SQL_C_LONG,
                                           SQL_INTEGER,4,0,&param1_val,0,&output_len);
param1_val=100;
rc = SQLExecute(hstmt);
/*we prepared a sql statement equivalent to "execute procedure testproc(100)".*/

Executing stored procedures

There are two methods an application can use to execute a stored procedure using Informix ODBC Driver:

  • EXECUTE PROCEDURE <procedure name>
  • {call <procedure name> }

The first syntax is provided by Informix database directly. For more information, please refer to the Informix database stored procedure syntax, available in the Information Center.

The second syntax belongs to the standard ODBC escape sequence. The benefit is that the same ODBC application can be used to execute the stored procedure against different database vendors, avoiding database vendor-specific calls.

To see a working example, create the following stored procedure in an Informix database.

Listing 3. Creating a test stored procedure
CREATE PROCEDURE testproc() returning int
RETURN 1234;
END PROCEDURE;

The examples below illustrate both types of syntax.

Listing 4. Executing the procedure using the execute procedure statement
rc = SQLExecDirectW (hstmt, L"execute procedure testproc ()", SQL_NTS );
Listing 5. Executing the procedure with call statement
rc = SQLExecDirectW (hstmt, L"{call testproc()}" , SQL_NTS ); 
rc = SQLFetch (hstmt);
rc = SQLGetData(hstmt, 1, SQL_C_LONG,&ret_val,4,&buffLen);

In the ret_val, the return result will be stored as 1234. This example just returned the value 1234. In a real-life scenario, there can be 1,000 lines of SQL statements that process very complex logic and return the output data to the user.

NOTE: Informix ODBC Driver will support OUT and INOUT parameters in {call <procedure name>} syntax. The following section provides examples.


Returning a value from a stored procedure

Create the following procedure in an Informix database.

Listing 6. Creating a simple procedure
CREATE PROCEDURE testproc() returning int
RETURN 100;
END PROCEDURE;

There are two ways to obtain the return value when you execute the stored procedure:

  • The SQLGetData() API
  • The SQLBindParameter() API

When the stored procedure returns a value, users can get the return value using the SQLGetData() API. The example below illustrates using it to retrieve the return value from a stored procedure.

Listing 7. Getting return value using the SQLGetData() API call
rc = SQLExecDirectW (hstmt, L"{call testproc()}" , SQL_NTS ); 
rc = SQLFetch (hstmt);
rc = SQLGetData(hstmt, 1, SQL_C_LONG,&ret_val,4,&buffLen);

At the end of successful execution the value of variable ret_val will be 100.

Using another method, you can retrieve the return value by binding a variable for it using the SQLBindParameter() API. Using this method, the variable gets attached to the stored procedure return value. Upon successful execution, the value 100 will be assigned to ret_val variable. As evident, this method is preferred over the previous method due to the smaller amount of coding and processing required. The following example explains the usage of SQLBindParameter() API to retrieve the return value from a stored procedure.

Listing 8. Getting return value using the SQLBindParamater() API call
 rc = SQLPrepare(hstmt, L"{?=call testproc()}" , SQL_NTS );
 rc = SQLBindParameter(hstmt,1, SQL_PARAM_OUTPUT, SQL_C_LONG,
                            SQL_INTEGER,4,0,&ret_val,0,&output_len);
 rc = SQLExecute(hstmt);

NOTE: When the stored procedure returns a value and contains OUT and INOUT parameters, only SQLBindParameter() can be used to get the data.


Executing a stored procedure with the OUT parameter

Create the following procedure in an Informix database.

Listing 9. Creating a sample procedure
CREATE PROCEDURE testprocout ( OUT param1 int)
let param1=3210;
END PROCEDURE;

The example below uses the OUT parameter in a stored procedure in an Informix ODBC application. Prior to 3.50.xC4, this would have failed. This example demonstrates how you should be able to get the data returned from the stored procedure as an OUT parameter. First, it prepares the query followed by binding the variable out_val, where the output of param1 stored procedure parameter output will be stored. The SQLExecute() API executes the stored procedure, and on successful execution, the variable out_val value gets populated to 3210.

Listing 10. Executing the stored procedure with the OUT parameter
  rc = SQLPrepare(hstmt,"{call testprocout(?)}", SQL_NTS);
  rc = SQLBindParameter(hstmt,1, SQL_PARAM_OUTPUT, SQL_C_LONG,
                          SQL_INTEGER,4,0,&out_val,0,&output_len);
  rc = SQLExecute(hstmt);

Executing a stored procedure with the INOUT parameter

Create the following procedure in the Informix database.

Listing 11. Creating a stored procedure
CREATE PROCEDURE testprocinout ( INOUT param1 int)
let param1=param1*2;
END PROCEDURE;

Like the above OUT parameter example, an application can use the same SQLBindParameter() API for attaching the INOUT parameter. The difference is going to be in terms of third parameter being passed as SQL_PARAM_INPUT_OUTPUT. Since it's an INOUT parameter, this will be used as input and output. As in the example below, inout_val variable is assigned a value of 100 and after successful execution of the SQLExecute() API, the value shall be changed to 200 (please see the stored procedure body as it's multiplying the input value by 2).

Listing 12. Executing the stored procedure with the INOUT parameter
rc = SQLPrepare(hstmt,"{call testprocinout(?)}", SQL_NTS);
rc = SQLBindParameter(hstmt,1, SQL_PARAM_INPUT_OUTPUT, SQL_C_LONG,
                           SQL_INTEGER,4,0,&inout_val,0,&output_len);
inout_val=100;
rc = SQLExecute(hstmt);

Executing a stored procedure with the OUT parameter on BLOB and CLOB data types

Create the following table and stored procedure in an Informix database for getting BLOB data through OUT parameter: create table tab_blob1(c_blob BLOB, c_int INTEGER, c_char VARCHAR(20));.

Insert one record (as per users choice) in the out_param_blob table.

Create the following procedure in the Informix database with an OUT parameter of BLOB data type.

Listing 13. Creating a sample procedure with an OUT parameter of BLOB data type
CREATE PROCEDURE out_param_blob(OUT blobparam BLOB, 
               OUT intparam int, OUT charparam VARCHAR(20))
select c_blob, c_int, c_char into blobparam, intparam, charparam from tab_blob1;
END PROCEDURE;

Execute the following statements to prepare the query and bind a variable with the parameter.

Listing 14. Executing the procedure with the OUT BLOB parameter
cbParm1 = SQL_NULL_DATA;
rc = SQLPrepare(hstmt, (UCHAR *)"{call out_param_blob(?, ?, ?)}", SQL_NTS);
rc = SQLBindParameter(hstmt, 1, SQL_PARAM_OUTPUT, SQL_C_BINARY, SQL_LONGVARBINARY,
		sizeof(blob_buffer), 0, blob_buffer, sizeof(blob_buffer), &cbParm1);
rc = SQLBindParameter(hstmt, 2, SQL_PARAM_OUTPUT, SQL_C_LONG, SQL_INTEGER, 
				3, 0, &sParm1, 0, &cbParm2);
rc = SQLBindParameter (hstmt, 3, SQL_PARAM_OUTPUT, SQL_C_CHAR, SQL_VARCHAR,
			 sizeof(schar), 0, schar, sizeof(schar), &cbParm3);
rc = SQLExecute(hstmt);

After successful execution, the blob_buffer will contain the BLOB column data retrieved from the stored procedure. To retrieve the BLOB data as an OUT parameter, use the ODBC SQL type as SQL_LONGVARBINARY and cbParm1 = SQL_NULL_DATA.

Create the following table and stored procedure in the Informix database for getting the CLOB data through OUT parameter: create table tab_clob1(c_clob CLOB, c_int INTEGER, c_char VARCHAR(20));.

Insert one record (as per users choice) in the out_param_clob table.

Create the following procedure in the Informix database with an OUT parameter of CLOB data type.

Listing 15. Creating a sample procedure with an OUT parameter of CLOB data type
CREATE PROCEDURE out_param_clob(OUT clobparam CLOB, 
			OUT intparam int, OUT charparam VARCHAR(20))
select c_clob, c_int, c_char into clobparam, intparam, charparam from tab_clob1;
END PROCEDURE;

Execute the following statements to prepare the query and bind a variable with the parameter.

Listing 16. Executing the stored procedure with the OUT CLOB parameter
cbParm1 = SQL_NULL_DATA;
rc = SQLPrepare(hstmt, (UCHAR *)"{call out_param_clob(?, ?, ?)}", SQL_NTS);
rc = SQLBindParameter(hstmt, 1, SQL_PARAM_OUTPUT, SQL_C_BINARY, SQL_LONGVARCHAR,
		sizeof(clob_buffer), 0, clob_buffer, sizeof(clob_buffer), &cbParm1);
rc = SQLBindParameter(hstmt, 2, SQL_PARAM_OUTPUT, SQL_C_LONG, SQL_INTEGER, 
				3, 0, &sParm1, 0, &cbParm2);
rc = SQLBindParameter (hstmt, 3, SQL_PARAM_OUTPUT, SQL_C_CHAR, SQL_VARCHAR,
			 sizeof(schar), 0, schar, sizeof(schar), &cbParm3);
rc = SQLExecute(hstmt);

After successful execution, the clob_buffer will contain the CLOB column data retrieved from the stored procedure. To retrieve the CLOB data as an OUT parameter, use the ODBC SQL type as SQL_LONGVARCHAR and cbParm1 = SQL_NULL_DATA.


Demo program

The following sample program demonstrates how to use the OUT and INOUT parameters for sample data types like INTEGER and CHARACTER using the Informix CSDK ODBC Driver API calls.

This program deletes the proc1 stored procedure if it exists in the database. Then creates a proc1 stored procedure with OUT and INOUT types in its signature. As you would observe for the INOUT type, its bind variable is idval as SQL_PARAM_INPUT_OUTPUT and provides a value (for example, 3) as input. Since this is using the INOUT parameter, its net result will be based on input value (3) and any operation taking place in the stored procedure (in this demo, it's multiplied by 100). Using CSDK ODBC Driver, it executes the stored procedure. During the execution, it is sending data to the stored procedure. After execution, it prints the output data received from the stored procedure call.

Listing 17. Demo application using OUT and INOUT and a return value
int main()
{
RETCODE retcode=SQL_SUCCESS;
SQLHENV henv = SQL_NULL_HENV;
SQLHDBC hdbc = SQL_NULL_HDBC;
SQLHSTMT hstmt= SQL_NULL_HSTMT;
char connectOutput[1024];
SQLINTEGER Connectresult;
char *dsn="dsn=newdsn";
int idval = 0, len=0,ret_val=0;
char nameval[50];
SQLCHAR *delstmt = (SQLCHAR *)"drop procedure proc1";
SQLCHAR *createstmt = 
      (SQLCHAR *)"create procedure proc1(INOUT id int, OUT name varchar(50))"
"  returning int "
"let id=100*id; "
"let name='Shesh'; "
"RETURN id*2; "
"end procedure; ";
SQLCHAR *callstmt = (SQLCHAR *)"{?=call proc1(?,?)} ";

retcode = SQLAllocHandle (SQL_HANDLE_ENV, NULL, &henv);
retcode = SQLSetEnvAttr (henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER) SQL_OV_ODBC3, 0);
retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);
retcode = SQLDriverConnect(hdbc, NULL ,dsn,SQL_NTS, connectOutput, sizeof(connectOutput),
                  &Connectresult , SQL_DRIVER_NOPROMPT);
retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
retcode = SQLExecDirect(hstmt, delstmt, SQL_NTS);
retcode = SQLExecDirect(hstmt, createstmt, SQL_NTS);
retcode = SQLPrepare(hstmt, callstmt, SQL_NTS);
retcode = SQLBindParameter (hstmt,1, SQL_PARAM_OUTPUT, SQL_C_LONG, SQL_INTEGER, 0, 0,
              (VOID *)&ret_val, 0,0);
retcode = SQLBindParameter (hstmt,2, SQL_PARAM_INPUT_OUTPUT, SQL_C_LONG, SQL_INTEGER,
                0, 0, (VOID *)&idval, 0,0);
idval=3;
retcode = SQLBindParameter (hstmt,3,SQL_PARAM_OUTPUT, SQL_C_CHAR, SQL_VARCHAR, 50, 0,
                (VOID *)&nameval, 50,&len);
retcode = SQLExecute(hstmt);
printf("Data id=%d , Name=%s , Return=%d\n", idval,nameval,ret_val);
SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
SQLDisconnect(hdbc);
SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
SQLFreeHandle(SQL_HANDLE_ENV, henv);
return retcode;
}

Output: Data id=300 , Name=Shesh , Return=600.

The following sample program demonstrates how to use the OUT and INOUT parameter types for various data types like BIGINT, BLOB, CLOB, and DATE in a stored procedure call. The goal of this program is as follows:

  1. Delete the table EmpDetail if it exists.
  2. Create an EmpDetail table where it stores the employee serial number, employee name, employee address, employee photo, and employee joining date.
  3. Insert one record into the table.
  4. Execute stored procedure, which will read the employee details from database EmpDetail table and return them through the OUT parameter.

The user needs to have two file names in the specified location containing the intended data:

  • c:\address.txt — This file contains the address of the employee.
  • c:\image.jpg — This file contains the photo of the employee. By default, the photo size should not exceed 50000 bytes. To add a bigger size image, configure #define IMAGESIZE 50000 to the actual size in bytes in the source code.

After the stored procedure call, the program prints the employee ID, name, address, and date of joining, and creates the same image in c:\out_image.jpg so the user can compare the photo with the input photo provided in c:\image.jpg.

Listing 18. Demo application using OUT and INOUT parameter with Bigint, BLOB, CLOB, and Date type
/*Put c:\address.txt and c:\image.jpg to verify the CLOB and BLOB type
Set the IMAGESIZE and ADDRSIZE according to the file size*/

#define IMAGESIZE 50000
#define ADDRSIZE 1024
int main()
{
RETCODE retcode;
SQLHENV henv = SQL_NULL_HENV;
SQLHDBC hdbc = SQL_NULL_HDBC;
SQLHSTMT hstmt= SQL_NULL_HSTMT;
char connectOutput[1024];
SQLINTEGER Connectresult;
char *dsn="dsn=newdsn";
SQLBIGINT id=0;
SQLCHAR name[100]={0,};
SQLDATE doj[20]={0,};
char image[IMAGESIZE], address[ADDRSIZE];
int length1=0,length2=SQL_NTS,length5=SQL_NTS;
int length3=SQL_NULL_DATA,length4=SQL_NULL_DATA;
FILE *fp;
SQLCHAR *drop_table = (SQLCHAR *)"drop table EmpDetail";
SQLCHAR *create_table = (SQLCHAR *)"create table EmpDetail"
"(empid bigint,empname varchar(100), empaddress CLOB, empimage BLOB,empdoj DATE)";
SQLCHAR *insert_table = (SQLCHAR *)"insert into EmpDetail values(4564789,"
"'Kollol Kumar Misra', filetoclob('c:\\address.txt','client'),"
"filetoblob('c:\\image.jpg','client'),'01-01-2001')";
SQLCHAR *delstmt = (SQLCHAR *)"drop procedure getempdetail";
SQLCHAR *createstmt = (SQLCHAR *)"create procedure getempdetail"
"(INOUT id BIGINT,OUT name VARCHAR(20), "
"OUT address CLOB, OUT image BLOB,OUT doj DATE)\n"
"select * into id,name,address,image,doj from EmpDetail;\n"
"end procedure;";
SQLCHAR *callstmt = (SQLCHAR *)"{call getempdetail(?,?,?,?,?)} ";
retcode = SQLAllocHandle (SQL_HANDLE_ENV, NULL, &henv);
retcode = SQLSetEnvAttr (henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER) SQL_OV_ODBC3, 0);
retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);
retcode = SQLDriverConnect(hdbc, NULL ,dsn,SQL_NTS, connectOutput,
          sizeof(connectOutput), &Connectresult , SQL_DRIVER_NOPROMPT);
retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
retcode = SQLExecDirect(hstmt, drop_table, SQL_NTS);
retcode = SQLExecDirect(hstmt, create_table, SQL_NTS);
retcode = SQLExecDirect(hstmt, insert_table, SQL_NTS);
retcode = SQLExecDirect(hstmt, delstmt, SQL_NTS);
retcode = SQLExecDirect(hstmt, createstmt, SQL_NTS);
retcode = SQLPrepare(hstmt, callstmt, SQL_NTS);
retcode = SQLBindParameter (hstmt,1,SQL_PARAM_INPUT_OUTPUT, SQL_C_SBIGINT,
          SQL_BIGINT, 0, 0, (VOID *)&id, 0,&length1);
retcode = SQLBindParameter (hstmt,2,SQL_PARAM_OUTPUT, SQL_C_CHAR, SQL_CHAR,
          sizeof(name), 0, (VOID *)name, sizeof(name),&length2);
retcode = SQLBindParameter (hstmt,3,SQL_PARAM_OUTPUT, SQL_C_BINARY,
                SQL_LONGVARCHAR, sizeof(address), 0, (VOID *)address, 
                sizeof(address),&length3);
retcode = SQLBindParameter (hstmt,4,SQL_PARAM_OUTPUT, SQL_C_BINARY,
          SQL_LONGVARBINARY, sizeof(image), 0, (VOID *)image, 
          sizeof(image),&length4);
retcode = SQLBindParameter (hstmt,5,SQL_PARAM_OUTPUT, SQL_C_CHAR,
          SQL_CHAR, sizeof(doj), 0, (VOID *)doj, sizeof(doj),&length5);
retcode = SQLExecute(hstmt);
printf("ID=%lld \nNAME=%s \nDOJ=%s \n",id,name,doj);
fp=fopen("c:\\out_image.jpg","w+b");
fwrite(image,1,length4,fp);
fclose(fp);
fp=fopen("c:\\out_address.txt","w+b");
fwrite(address,1,length3,fp);
fclose(fp);
SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
SQLDisconnect(hdbc);
SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
SQLFreeHandle(SQL_HANDLE_ENV, henv);
return retcode;
}

Output:

ID=4564789
NAME=Kollol Kumar Misra
DOJ=2001-01-01

Compare the out_image.jpg and out_address.txt files with the original files to ensure what was inserted is what has been retrieved correctly.


Conclusion

This article has demonstrated the use of the OUT and INOUT parameters using Informix ODBC Driver. Before the CSDK 3.50.xC4 release, CSDK ODBC Driver was not capable of handling the OUT and INOUT parameter types. So when users tried to execute the stored procedure calls with the OUT and INOUT parameters, they encountered errors from the driver. As mentioned, OUT and INOUT parameters are the standard types and are present in most databases. After the CSDK 3.50.xC4 release, CSDK ODBC Driver started supporting the OUT and INOUT parameter types in procedure calls. This helps you write and execute more complex stored procedure code and call the stored procedure inside an application using CSDK ODBC Driver. The various sample C code snippets demonstrate how to write applications using the Informix ODBC Driver. In several places, notes indicate the correct way to handle stored procedure calls with OUT and INOUT parameters.


Download

DescriptionNameSize
Parametersoutparam.zip227KB

Resources

Learn

Get products and technologies

  • Build your next development project with IBM trial software, available for download directly from developerWorks.
  • Now you can use DB2 for free. Download DB2 Express-C, a no-charge version of DB2 Express Edition for the community that offers the same core data features as DB2 Express Edition and provides a solid base to build and deploy applications.

Discuss

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into Information management on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Information Management
ArticleID=818867
ArticleTitle=OUT and INOUT parameter support for stored procedure calls in Informix ODBC Driver
publish-date=05312012