/*
* IBM_DB::bind_param -- Binds a Ruby variable to an SQL statement parameter
*
* ===Description
* bool IBM_DB::bind_param ( resource stmt, int parameter-number, string variable-name [, int parameter-type
* [, int data-type [, int precision [, int scale [, int size[]]]]]] )
*
* Binds a Ruby variable to an SQL statement parameter in a statement resource returned by IBM_DB::prepare().
* This function gives you more control over the parameter type, data type, precision, and scale for
* the parameter than simply passing the variable as part of the optional input array to IBM_DB::execute().
*
* ===Parameters
*
* stmt
* A prepared statement returned from IBM_DB::prepare().
*
* parameter-number
* Specifies the 1-indexed position of the parameter in the prepared statement.
*
* variable-name
* A string specifying the name of the Ruby variable to bind to the parameter specified by parameter-number.
*
* parameter-type
* A constant specifying whether the Ruby variable should be bound to the SQL parameter as an input parameter
* (SQL_PARAM_INPUT), an output parameter (SQL_PARAM_OUTPUT), or as a parameter that accepts input and returns output
* (SQL_PARAM_INPUT_OUTPUT). To avoid memory overhead, you can also specify PARAM_FILE to bind the Ruby variable
* to the name of a file that contains large object (BLOB, CLOB, or DBCLOB) data.
*
* data-type
* A constant specifying the SQL data type that the Ruby variable should be bound as: one of SQL_BINARY,
* DB2_CHAR, DB2_DOUBLE, or DB2_LONG .
*
* precision
* Specifies the precision that the variable should be bound to the database.
*
* scale
* Specifies the scale that the variable should be bound to the database.
*
* size
* Specifies the size that should be retreived from an INOUT/OUT parameter.
*
* ===Return Values
*
* Returns TRUE on success or FALSE on failure.
*/
VALUE ibm_db_bind_param(int argc, VALUE *argv, VALUE self)
{
char *varname = NULL;
char error[DB2_MAX_ERR_MSG_LEN];
long varname_len;
long param_type = SQL_PARAM_INPUT;
/* LONG types used for data being passed in */
SQLUSMALLINT param_no = 0;
long data_type = 0;
long precision = 0;
long scale = 0;
long size = 0;
SQLSMALLINT sql_data_type = 0;
SQLUINTEGER sql_precision = 0;
SQLSMALLINT sql_scale = 0;
SQLSMALLINT sql_nullable = SQL_NO_NULLS;
VALUE stmt = Qnil;
stmt_handle *stmt_res;
int rc = 0;
VALUE r_param_no, r_varname, r_param_type=Qnil, r_size=Qnil;
VALUE r_data_type=Qnil, r_precision=Qnil, r_scale=Qnil;
rb_scan_args(argc, argv, "35", &stmt, &r_param_no, &r_varname,
&r_param_type, &r_data_type, &r_precision, &r_scale, &r_size);
param_no = NUM2INT(r_param_no);
varname = rb_str2cstr(r_varname, &varname_len);
if (!NIL_P(r_param_type)) param_type = NUM2LONG(r_param_type);
if (!NIL_P(r_data_type)) data_type = NUM2LONG(r_data_type);
if (!NIL_P(r_precision)) precision = NUM2LONG(r_precision);
if (!NIL_P(r_scale)) scale = NUM2LONG(r_scale);
if (!NIL_P(r_size)) size = NUM2LONG(r_size);
if (!NIL_P(stmt)) {
Data_Get_Struct(stmt, stmt_handle, stmt_res);
/* Check for Param options */
switch (argc) {
/* if argc == 3, then the default value for param_type will be used */
case 3:
param_type = SQL_PARAM_INPUT;
rc = SQLDescribeParam((SQLHSTMT)stmt_res->hstmt, (SQLUSMALLINT)param_no, &sql_data_type, &sql_precision, &sql_scale, &sql_nullable);
if ( rc == SQL_ERROR ) {
_ruby_ibm_db_check_sql_errors(stmt_res->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
sprintf(error, "Describe Param Failed: %s", IBM_DB_G(__ruby_stmt_err_msg));
rb_throw(error, Qnil);
return Qfalse;
}
/* Add to cache */
_ruby_ibm_db_add_param_cache( stmt_res, param_no, varname, varname_len, param_type, size, sql_data_type, sql_precision, sql_scale, sql_nullable );
break;
case 4:
rc = SQLDescribeParam((SQLHSTMT)stmt_res->hstmt, (SQLUSMALLINT)param_no, &sql_data_type, &sql_precision, &sql_scale, &sql_nullable);
if ( rc == SQL_ERROR ) {
_ruby_ibm_db_check_sql_errors(stmt_res->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
sprintf(error, "Describe Param Failed: %s", IBM_DB_G(__ruby_stmt_err_msg));
rb_throw(error, Qnil);
return Qfalse;
}
/* Add to cache */
_ruby_ibm_db_add_param_cache( stmt_res, param_no, varname, varname_len, param_type, size, sql_data_type, sql_precision, sql_scale, sql_nullable );
break;
case 5:
rc = SQLDescribeParam((SQLHSTMT)stmt_res->hstmt, (SQLUSMALLINT)param_no, &sql_data_type, &sql_precision, &sql_scale, &sql_nullable);
if ( rc == SQL_ERROR ) {
_ruby_ibm_db_check_sql_errors(stmt_res->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
sprintf(error, "Describe Param Failed: %s", IBM_DB_G(__ruby_stmt_err_msg));
rb_throw(error, Qnil);
return Qfalse;
}
sql_data_type = (SQLSMALLINT)data_type;
/* Add to cache */
_ruby_ibm_db_add_param_cache( stmt_res, param_no, varname, varname_len, param_type, size, sql_data_type, sql_precision, sql_scale, sql_nullable );
break;
case 6:
rc = SQLDescribeParam((SQLHSTMT)stmt_res->hstmt, (SQLUSMALLINT)param_no, &sql_data_type, &sql_precision, &sql_scale, &sql_nullable);
if ( rc == SQL_ERROR ) {
_ruby_ibm_db_check_sql_errors(stmt_res->hstmt, SQL_HANDLE_STMT, rc, 1, NULL, -1, 1);
sprintf(error, "Describe Param Failed: %s", IBM_DB_G(__ruby_stmt_err_msg));
rb_throw(error, Qnil);
return Qfalse;
}
sql_data_type = (SQLSMALLINT)data_type;
sql_precision = (SQLUINTEGER)precision;
/* Add to cache */
_ruby_ibm_db_add_param_cache( stmt_res, param_no, varname, varname_len, param_type, size, sql_data_type, sql_precision, sql_scale, sql_nullable );
break;
case 7:
case 8:
/* Cache param data passed */
/* I am using a linked list of nodes here because I dont know before hand how many params are being passed in/bound. */
/* To determine this, a call to SQLNumParams is necessary. This is take away any advantages an array would have over linked list access */
/* Data is being copied over to the correct types for subsequent CLI call because this might cause problems on other platforms such as AIX */
sql_data_type = (SQLSMALLINT)data_type;
sql_precision = (SQLUINTEGER)precision;
sql_scale = (SQLSMALLINT)scale;
_ruby_ibm_db_add_param_cache( stmt_res, param_no, varname, varname_len, param_type, size, sql_data_type, sql_precision, sql_scale, sql_nullable );
break;
default:
/* WRONG_PARAM_COUNT; */
return Qfalse;
}
/* end Switch */
/* We bind data with DB2 CLI in IBM_DB::execute() */
/* This will save network flow if we need to override params in it */
return Qtrue;
} else {
rb_throw("Supplied parameter is invalid", Qnil);
return Qfalse;
}
}