| 
      
      
      From: Michael N. <mne...@us...> - 2002-09-05 09:57:17
      
     | 
| Update of /cvsroot/ruby-dbi/subprojects/ruby-db2/ext/db2
In directory usw-pr-cvs1:/tmp/cvs-serv2947/ruby-db2/ext/db2
Added Files:
	constants.h db2cli.c extconf.rb 
Log Message:
initial import from local CVS repository
--- NEW FILE: constants.h ---
rb_define_const(mDB2CLI, "SQL_SUCCESS", INT2NUM(SQL_SUCCESS));
rb_define_const(mDB2CLI, "SQL_SUCCESS_WITH_INFO", INT2NUM(SQL_SUCCESS_WITH_INFO));
rb_define_const(mDB2CLI, "SQL_INVALID_HANDLE", INT2NUM(SQL_INVALID_HANDLE));
rb_define_const(mDB2CLI, "SQL_STILL_EXECUTING", INT2NUM(SQL_STILL_EXECUTING));
rb_define_const(mDB2CLI, "SQL_ERROR", INT2NUM(SQL_ERROR));
rb_define_const(mDB2CLI, "SQL_NO_DATA_FOUND", INT2NUM(SQL_NO_DATA_FOUND));
rb_define_const(mDB2CLI, "SQL_NULL_DATA", INT2NUM(SQL_NULL_DATA));
rb_define_const(mDB2CLI, "SQL_HANDLE_ENV", INT2NUM(SQL_HANDLE_ENV));
rb_define_const(mDB2CLI, "SQL_HANDLE_DBC", INT2NUM(SQL_HANDLE_DBC));
rb_define_const(mDB2CLI, "SQL_HANDLE_STMT", INT2NUM(SQL_HANDLE_STMT));
rb_define_const(mDB2CLI, "SQL_HANDLE_DESC", INT2NUM(SQL_HANDLE_DESC));
rb_define_const(mDB2CLI, "SQL_NULL_HANDLE", INT2NUM(SQL_NULL_HANDLE));
rb_define_const(mDB2CLI, "SQL_NULL_HENV", INT2NUM(SQL_NULL_HENV));
rb_define_const(mDB2CLI, "SQL_NULL_HDBC", INT2NUM(SQL_NULL_HDBC));
rb_define_const(mDB2CLI, "SQL_NULL_HSTMT", INT2NUM(SQL_NULL_HSTMT));
rb_define_const(mDB2CLI, "SQL_NULL_HDESC", INT2NUM(SQL_NULL_HDESC));
rb_define_const(mDB2CLI, "SQL_NO_NULLS", INT2NUM(SQL_NO_NULLS));
rb_define_const(mDB2CLI, "SQL_NULLABLE", INT2NUM(SQL_NULLABLE));
rb_define_const(mDB2CLI, "SQL_COMMIT", INT2NUM(SQL_COMMIT));
rb_define_const(mDB2CLI, "SQL_ROLLBACK", INT2NUM(SQL_ROLLBACK));
rb_define_const(mDB2CLI, "SQL_TRUE", INT2NUM(SQL_TRUE));
rb_define_const(mDB2CLI, "SQL_FALSE", INT2NUM(SQL_FALSE));
rb_define_const(mDB2CLI, "SQL_MAX_DSN_LENGTH", INT2NUM(SQL_MAX_DSN_LENGTH));
rb_define_const(mDB2CLI, "SQL_BIGINT", INT2NUM(SQL_BIGINT));
rb_define_const(mDB2CLI, "SQL_BLOB", INT2NUM(SQL_BLOB));
rb_define_const(mDB2CLI, "SQL_BLOB_LOCATOR", INT2NUM(SQL_BLOB_LOCATOR));
rb_define_const(mDB2CLI, "SQL_CHAR", INT2NUM(SQL_CHAR));
rb_define_const(mDB2CLI, "SQL_BINARY", INT2NUM(SQL_BINARY));
rb_define_const(mDB2CLI, "SQL_CLOB", INT2NUM(SQL_CLOB));
rb_define_const(mDB2CLI, "SQL_CLOB_LOCATOR", INT2NUM(SQL_CLOB_LOCATOR));
rb_define_const(mDB2CLI, "SQL_TYPE_DATE", INT2NUM(SQL_TYPE_DATE));
rb_define_const(mDB2CLI, "SQL_DBCLOB", INT2NUM(SQL_DBCLOB));
rb_define_const(mDB2CLI, "SQL_DBCLOB_LOCATOR", INT2NUM(SQL_DBCLOB_LOCATOR));
rb_define_const(mDB2CLI, "SQL_DECIMAL", INT2NUM(SQL_DECIMAL));
rb_define_const(mDB2CLI, "SQL_DOUBLE", INT2NUM(SQL_DOUBLE));
rb_define_const(mDB2CLI, "SQL_FLOAT", INT2NUM(SQL_FLOAT));
rb_define_const(mDB2CLI, "SQL_GRAPHIC", INT2NUM(SQL_GRAPHIC));
rb_define_const(mDB2CLI, "SQL_INTEGER", INT2NUM(SQL_INTEGER));
rb_define_const(mDB2CLI, "SQL_LONGVARCHAR", INT2NUM(SQL_LONGVARCHAR));
rb_define_const(mDB2CLI, "SQL_LONGVARBINARY", INT2NUM(SQL_LONGVARBINARY));
rb_define_const(mDB2CLI, "SQL_LONGVARGRAPHIC", INT2NUM(SQL_LONGVARGRAPHIC));
rb_define_const(mDB2CLI, "SQL_NUMERIC", INT2NUM(SQL_NUMERIC));
rb_define_const(mDB2CLI, "SQL_REAL", INT2NUM(SQL_REAL));
rb_define_const(mDB2CLI, "SQL_SMALLINT", INT2NUM(SQL_SMALLINT));
rb_define_const(mDB2CLI, "SQL_TYPE_TIME", INT2NUM(SQL_TYPE_TIME));
rb_define_const(mDB2CLI, "SQL_TYPE_TIMESTAMP", INT2NUM(SQL_TYPE_TIMESTAMP));
rb_define_const(mDB2CLI, "SQL_VARCHAR", INT2NUM(SQL_VARCHAR));
rb_define_const(mDB2CLI, "SQL_VARBINARY", INT2NUM(SQL_VARBINARY));
rb_define_const(mDB2CLI, "SQL_VARGRAPHIC", INT2NUM(SQL_VARGRAPHIC));
rb_define_const(mDB2CLI, "SQL_FETCH_NEXT", INT2NUM(SQL_FETCH_NEXT));
rb_define_const(mDB2CLI, "SQL_FETCH_PRIOR", INT2NUM(SQL_FETCH_PRIOR));
rb_define_const(mDB2CLI, "SQL_FETCH_RELATIVE", INT2NUM(SQL_FETCH_RELATIVE));
rb_define_const(mDB2CLI, "SQL_FETCH_ABSOLUTE", INT2NUM(SQL_FETCH_ABSOLUTE));
rb_define_const(mDB2CLI, "SQL_FETCH_FIRST", INT2NUM(SQL_FETCH_FIRST));
rb_define_const(mDB2CLI, "SQL_FETCH_LAST", INT2NUM(SQL_FETCH_LAST));
rb_define_const(mDB2CLI, "SQL_FETCH_BOOKMARK", INT2NUM(SQL_FETCH_BOOKMARK));
rb_define_const(mDB2CLI, "SQL_CLOSE", INT2NUM(SQL_CLOSE));
rb_define_const(mDB2CLI, "SQL_DROP", INT2NUM(SQL_DROP));
rb_define_const(mDB2CLI, "SQL_UNBIND", INT2NUM(SQL_UNBIND));
rb_define_const(mDB2CLI, "SQL_RESET_PARAMS", INT2NUM(SQL_RESET_PARAMS));
rb_define_const(mDB2CLI, "SQL_DESC_AUTO_UNIQUE_VALUE", INT2NUM(SQL_DESC_AUTO_UNIQUE_VALUE));
rb_define_const(mDB2CLI, "SQL_DESC_CASE_SENSITIVE", INT2NUM(SQL_DESC_CASE_SENSITIVE));
rb_define_const(mDB2CLI, "SQL_DESC_CATALOG_NAME", INT2NUM(SQL_DESC_CATALOG_NAME));
rb_define_const(mDB2CLI, "SQL_DESC_COUNT", INT2NUM(SQL_DESC_COUNT));
rb_define_const(mDB2CLI, "SQL_DESC_DISPLAY_SIZE", INT2NUM(SQL_DESC_DISPLAY_SIZE));
rb_define_const(mDB2CLI, "SQL_DESC_LABEL", INT2NUM(SQL_DESC_LABEL));
rb_define_const(mDB2CLI, "SQL_DESC_DISTINCT_TYPE", INT2NUM(SQL_DESC_DISTINCT_TYPE));
rb_define_const(mDB2CLI, "SQL_DESC_OCTET_LENGTH", INT2NUM(SQL_DESC_OCTET_LENGTH));
rb_define_const(mDB2CLI, "SQL_DESC_FIXED_PREC_SCALE", INT2NUM(SQL_DESC_FIXED_PREC_SCALE));
rb_define_const(mDB2CLI, "SQL_DESC_NAME", INT2NUM(SQL_DESC_NAME));
rb_define_const(mDB2CLI, "SQL_DESC_NULLABLE", INT2NUM(SQL_DESC_NULLABLE));
rb_define_const(mDB2CLI, "SQL_DESC_SCHEMA_NAME", INT2NUM(SQL_DESC_SCHEMA_NAME));
rb_define_const(mDB2CLI, "SQL_DESC_PRECISION", INT2NUM(SQL_DESC_PRECISION));
rb_define_const(mDB2CLI, "SQL_DESC_SCALE", INT2NUM(SQL_DESC_SCALE));
rb_define_const(mDB2CLI, "SQL_DESC_SEARCHABLE", INT2NUM(SQL_DESC_SEARCHABLE));
rb_define_const(mDB2CLI, "SQL_DESC_TABLE_NAME", INT2NUM(SQL_DESC_TABLE_NAME));
rb_define_const(mDB2CLI, "SQL_DESC_TYPE", INT2NUM(SQL_DESC_TYPE));
rb_define_const(mDB2CLI, "SQL_DESC_TYPE_NAME", INT2NUM(SQL_DESC_TYPE_NAME));
rb_define_const(mDB2CLI, "SQL_DESC_UNSIGNED", INT2NUM(SQL_DESC_UNSIGNED));
rb_define_const(mDB2CLI, "SQL_DESC_UPDATABLE", INT2NUM(SQL_DESC_UPDATABLE));
rb_define_const(mDB2CLI, "SQL_DESC_BASE_COLUMN_NAME", INT2NUM(SQL_DESC_BASE_COLUMN_NAME));
rb_define_const(mDB2CLI, "SQL_DESC_BASE_TABLE_NAME", INT2NUM(SQL_DESC_BASE_TABLE_NAME));
rb_define_const(mDB2CLI, "SQL_DESC_CONCISE_TYPE", INT2NUM(SQL_DESC_CONCISE_TYPE));
rb_define_const(mDB2CLI, "SQL_DESC_LENGTH", INT2NUM(SQL_DESC_LENGTH));
rb_define_const(mDB2CLI, "SQL_DESC_LITERAL_PREFIX", INT2NUM(SQL_DESC_LITERAL_PREFIX));
rb_define_const(mDB2CLI, "SQL_DESC_LITERAL_SUFFIX", INT2NUM(SQL_DESC_LITERAL_SUFFIX));
rb_define_const(mDB2CLI, "SQL_DESC_LOCAL_TYPE_NAME", INT2NUM(SQL_DESC_LOCAL_TYPE_NAME));
rb_define_const(mDB2CLI, "SQL_DESC_NUM_PREC_RADIX", INT2NUM(SQL_DESC_NUM_PREC_RADIX));
rb_define_const(mDB2CLI, "SQL_DESC_UNNAMED", INT2NUM(SQL_DESC_UNNAMED));
--- NEW FILE: db2cli.c ---
/*
 * IBM DB2 CLI 5.0 (Call Level Interface) Module for Ruby
 *
 * file:   db2cli.c
 * author: Michael Neumann (ne...@s-...)
 * id:     $Id: db2cli.c,v 1.1 2002/09/05 09:57:13 mneumann Exp $
 * 
 * Copyright (C) 2001 by Michael Neumann.
 * Released under the same terms as Ruby itself.
 *
 */
/**********************************************************************
 Description:
 ======================================================================
 - SQLRETURN is always returned as Ruby-Integer (Fixnum or Bignum) 
 - any SQLHANDLE-type (SQLHENV, SQLHDBC, SQLHSTMT, SQLHDESC) is given
   or returned as Ruby-Integer (Fixnum or Bignum)
 - SQLSMALLINT etc. are all Ruby-Integer
**********************************************************************/
/**********************************************************************
 Strange Things:
 ======================================================================
 - after allocating an Environment-Handle "p 5.7" gives "5,7.0" on my
   system (in Germany correct would be "5,7"). Fault of Linux ????
**********************************************************************/
/* Includes */
#include <stdio.h>
#include <stdlib.h>
#include "sqlcli1.h"
#include "ruby.h"
/* Macros */
#define TO_C_INT(val)    NUM2INT(val)
#define TO_RUBY_INT(val) INT2NUM(val)
#define MUST_BE_STRING(val) Check_Type(val, T_STRING)
#define MAX(a,b) ((a) > (b) ? (a) : (b)) 
#define MIN(a,b) ((a) < (b) ? (a) : (b)) 
/* Global Variables */
static VALUE mDB2CLI;
static VALUE cDate, cTime, cTimestamp;
static VALUE objNull; /* object for a SQL NULL value */
/* Functions */
/*******************************************************
 SQLAllocHandle
 =======================================================
 PARAMS:   handle_type, input_handle : Integer
 RETURNS:  rc, output_handle : Integer
********************************************************/
static VALUE
db2_SQLAllocHandle(self, handle_type, input_handle) 
  VALUE self;
  VALUE handle_type, input_handle;
{
  SQLRETURN rc;
  SQLHANDLE output_handle;
  rc = SQLAllocHandle(
    (SQLSMALLINT) TO_C_INT(handle_type),
    (SQLHANDLE)   TO_C_INT(input_handle),
    (SQLHANDLE*)  &output_handle
  );
  return rb_ary_new3(2, TO_RUBY_INT(rc), TO_RUBY_INT(output_handle));
} 
/*******************************************************
 SQLFreeHandle
 =======================================================
 PARAMS:   handle_type, handle : Integer
 RETURNS:  rc : Integer
********************************************************/
static VALUE
db2_SQLFreeHandle(self, handle_type, handle)
  VALUE self;
  VALUE handle_type, handle;
{
  SQLRETURN rc;
  rc = SQLFreeHandle(
    (SQLSMALLINT) TO_C_INT(handle_type),
    (SQLHANDLE)   TO_C_INT(handle) 
  );
  return TO_RUBY_INT(rc);  
} 
/*******************************************************
 SQLFreeStmt
 =======================================================
 PARAMS:   statement_handle, option : Integer
 RETURNS:  rc : Integer
********************************************************/
static VALUE
db2_SQLFreeStmt(self, statement_handle, option)
  VALUE self;
  VALUE statement_handle, option;
{
  SQLRETURN rc;
  rc = SQLFreeStmt(
    (SQLHSTMT)     TO_C_INT(statement_handle),  
    (SQLUSMALLINT) TO_C_INT(option)
  );
  return TO_RUBY_INT(rc);  
} 
/*******************************************************
 SQLDataSources
 =======================================================
 PARAMS:   environment_handle : Integer,
           direction          : Integer,
           server_name_length : Integer,   (buffer-length)
           description_length : Integer    (buffer-length)
 RETURNS:  rc                 : Integer,
           server_name        : String,
           server_name_length : Integer,   (bytes available)
           description        : String, 
           description_length : Integer    (bytes available) 
********************************************************/
static VALUE
db2_SQLDataSources(self, environment_handle, direction, 
                   server_name_length, description_length)
  VALUE self;
  VALUE environment_handle, direction;
  VALUE server_name_length, description_length;
{
  SQLRETURN rc;
  SQLCHAR*    server_name;
  SQLCHAR*    description;
  SQLSMALLINT sl;          /* server_name_length      */
  SQLSMALLINT dl;          /* description_length      */
  SQLSMALLINT sn_length;   /* real server_name_length */ 
  SQLSMALLINT ds_length;   /* real description_length */ 
  VALUE       retval;
  sl = TO_C_INT(server_name_length);
  dl = TO_C_INT(description_length);
  server_name = (SQLCHAR*) ALLOC_N(SQLCHAR, sl);
  description = (SQLCHAR*) ALLOC_N(SQLCHAR, dl);
  rc = SQLDataSources(
    (SQLHENV)      TO_C_INT(environment_handle),
    (SQLUSMALLINT) TO_C_INT(direction),
    (SQLCHAR*)     server_name,
    (SQLSMALLINT)  sl,
    (SQLSMALLINT*) &sn_length,
    (SQLCHAR*)     description,
    (SQLSMALLINT)  dl,
    (SQLSMALLINT*) &ds_length
 );
  retval = rb_ary_new3( 
    5,
    TO_RUBY_INT(rc),
    rb_str_new(server_name, MIN(sl, sn_length)),
    TO_RUBY_INT(sn_length),
    rb_str_new(description, MIN(dl, ds_length)),
    TO_RUBY_INT(ds_length)
  );
  free((void*)description);
  free((void*)server_name);
  return retval; 
} 
/*******************************************************
 SQLConnect
 =======================================================
 PARAMS:   connection_handle : Integer,
           server_name, user_name, auth : String
 RETURNS:  rc : Integer
********************************************************/
static VALUE
db2_SQLConnect(self, connection_handle, server_name, user_name, auth)
  VALUE self;
  VALUE connection_handle, server_name, user_name, auth;
{
  SQLRETURN rc;
  MUST_BE_STRING(server_name);
  MUST_BE_STRING(user_name);
  MUST_BE_STRING(auth);
  rc = SQLConnect(
    (SQLHDBC)      TO_C_INT(connection_handle),
    (SQLCHAR *FAR) RSTRING(server_name)->ptr,
    (SQLSMALLINT)  RSTRING(server_name)->len,
    (SQLCHAR *FAR) RSTRING(user_name)->ptr,
    (SQLSMALLINT)  RSTRING(user_name)->len,
    (SQLCHAR *FAR) RSTRING(auth)->ptr,
    (SQLSMALLINT)  RSTRING(auth)->len
  );
  return TO_RUBY_INT(rc); 
} 
/*******************************************************
 SQLDisconnect
 =======================================================
 PARAMS:   connection_handle : Integer
 RETURNS:  rc : Integer
********************************************************/
static VALUE
db2_SQLDisconnect(self, connection_handle)
  VALUE self;
  VALUE connection_handle;
{
  SQLRETURN rc;
  rc = SQLDisconnect(
    (SQLHDBC) TO_C_INT(connection_handle)
  );
  return TO_RUBY_INT(rc); 
}
/*******************************************************
 SQLPrepare
 =======================================================
 PARAMS:   statement_handle : Integer,
           statement_text : String
 RETURNS:  rc : Integer
********************************************************/
static VALUE
db2_SQLPrepare(self, statement_handle, statement_text)
  VALUE self;
  VALUE statement_handle, statement_text;
{
  SQLRETURN rc;
  MUST_BE_STRING(statement_text);
  rc = SQLPrepare(
    (SQLHSTMT)     TO_C_INT(statement_handle),
    (SQLCHAR *FAR) RSTRING(statement_text)->ptr,
    (SQLINTEGER)   RSTRING(statement_text)->len
  );
  return TO_RUBY_INT(rc); 
} 
/*******************************************************
 SQLNumResultCols
 =======================================================
 PARAMS:   statement_handle : Integer
 RETURNS:  rc, column_count : Integer
********************************************************/
static VALUE
db2_SQLNumResultCols(self, statement_handle)
  VALUE self;
  VALUE statement_handle;
{
  SQLRETURN   rc;
  SQLSMALLINT column_count; 
  rc = SQLNumResultCols(
    (SQLHSTMT)     TO_C_INT(statement_handle),
    (SQLSMALLINT*) &column_count
  );
  return rb_ary_new3(2, TO_RUBY_INT(rc), TO_RUBY_INT(column_count));
} 
/*******************************************************
 SQLDescribeCol
 =======================================================
 PARAMS:   statement_handle : Integer,
           column_number    : Integer,
           buffer_length    : Integer (for column_name)
 RETURNS:  rc               : Integer, 
           column_name      : String | nil,
           name_length      : Integer,
           data_type        : Integer,
           column_size      : Integer,
           decimal_digits   : Integer,
           nullable         : Integer
********************************************************/
static VALUE
db2_SQLDescribeCol(self, statement_handle, column_number, buffer_length)
  VALUE self;
  VALUE statement_handle, column_number, buffer_length;
{
  SQLRETURN rc;
  SQLCHAR*  colname_ptr;
  SQLSMALLINT name_length, data_type, decimal_digits, nullable;
  SQLUINTEGER column_size;
  SQLSMALLINT bl;  /* buffer_length */
  VALUE retval;
    
  bl          = TO_C_INT(buffer_length);
  colname_ptr = (SQLCHAR*) ALLOC_N(SQLCHAR, bl);
  rc = SQLDescribeCol(
    (SQLHSTMT)     TO_C_INT(statement_handle),
    (SQLUSMALLINT) TO_C_INT(column_number),
    (SQLCHAR *)    colname_ptr,
    (SQLSMALLINT)  bl,
    (SQLSMALLINT*) &name_length,
    (SQLSMALLINT*) &data_type,
    (SQLUINTEGER*) &column_size,
    (SQLSMALLINT*) &decimal_digits,
    (SQLSMALLINT*) &nullable
  );
  retval = rb_ary_new3( 
    7, 
    TO_RUBY_INT(rc), 
    colname_ptr == NULL ? Qnil : rb_str_new(colname_ptr, MIN(name_length, bl)),
    TO_RUBY_INT(name_length),
    TO_RUBY_INT(data_type),
    TO_RUBY_INT(column_size),
    TO_RUBY_INT(decimal_digits),
    TO_RUBY_INT(nullable) 
  );
  
  free(colname_ptr);
  return retval; 
}
/*******************************************************
 SQLColAttribute
 =======================================================
 PARAMS:   statement_handle    : Integer,
           column_number       : Integer,
           field_identifier    : Integer,
           buffer_length       : Integer | nil (nil == numeric_attribute) 
 RETURNS:  if numeric_attribute (buffer_length==nil):
             rc                  : Integer, 
             numeric_attribute   : Integer
           elsif character_attribute (buffer_length != nil):
             rc                  : Integer, 
             character_attribute : String,
             string_length       : Integer 
********************************************************/
static VALUE
db2_SQLColAttribute(self, statement_handle, column_number, field_identifier, buffer_length)
  VALUE self;
  VALUE statement_handle, column_number, field_identifier, buffer_length;
{
  SQLRETURN   rc;
  SQLSMALLINT bl;  /* buffer_length */
  SQLPOINTER  character_attr_ptr; 
  SQLSMALLINT string_length;
  signed long numeric_attribute; 
  VALUE retval;
    
  if (NIL_P(buffer_length) != 0) {
    /* numeric_attribute */
    bl = 0;
    character_attr_ptr = NULL;
  }
  else {
    /* character_attribute */
    bl = TO_C_INT(buffer_length);
    character_attr_ptr = (SQLPOINTER) ALLOC_N(char, bl);
  }
  rc = SQLColAttribute(
    (SQLHSTMT)     TO_C_INT(statement_handle),
    (SQLUSMALLINT) TO_C_INT(column_number),
    (SQLSMALLINT)  TO_C_INT(field_identifier),
    (SQLPOINTER)   character_attr_ptr,
    (SQLSMALLINT)  bl,
    (SQLSMALLINT*) &string_length,
    (SQLPOINTER)   &numeric_attribute
  );
  if (NIL_P(buffer_length) != 0) {
    /* numeric_attribute */
    retval = rb_ary_new3( 
      2, 
      TO_RUBY_INT(rc), 
      TO_RUBY_INT(numeric_attribute)
    );
  }
  else {
    /* character_attribute */
    retval = rb_ary_new3( 
      3, 
      TO_RUBY_INT(rc), 
      rb_str_new(character_attr_ptr, MIN(string_length, bl)),
      TO_RUBY_INT(string_length)
    );
    free(character_attr_ptr);
  }
  return retval; 
}
/*******************************************************
 SQLExecDirect
 =======================================================
 PARAMS:   statement_handle : Integer,
           statement_text : String
 RETURNS:  rc : Integer
********************************************************/
static VALUE
db2_SQLExecDirect(self, statement_handle, statement_text)
  VALUE self;
  VALUE statement_handle, statement_text;
{
  SQLRETURN rc;
  MUST_BE_STRING(statement_text);
  rc = SQLExecDirect(
    (SQLHSTMT)     TO_C_INT(statement_handle),
    (SQLCHAR *FAR) RSTRING(statement_text)->ptr,
    (SQLINTEGER)   RSTRING(statement_text)->len
  );
  return TO_RUBY_INT(rc); 
} 
/*******************************************************
 SQLExecute
 =======================================================
 PARAMS:   statement_handle : Integer
 RETURNS:  rc : Integer
********************************************************/
static VALUE
db2_SQLExecute(self, statement_handle)
  VALUE self;
  VALUE statement_handle;
{
  SQLRETURN rc;
  rc = SQLExecute(
    (SQLHSTMT) TO_C_INT(statement_handle)
  );
  return TO_RUBY_INT(rc); 
} 
/*******************************************************
 SQLRowCount
 =======================================================
 PARAMS:   statement_handle : Integer
 RETURNS:  rc, row_count : Integer
********************************************************/
static VALUE
db2_SQLRowCount(self, statement_handle)
  VALUE self;
  VALUE statement_handle;
{
  SQLRETURN  rc;
  SQLINTEGER row_count; 
  rc = SQLRowCount(
    (SQLHSTMT)    TO_C_INT(statement_handle),
    (SQLINTEGER*) &row_count
  );
  return rb_ary_new3(2, TO_RUBY_INT(rc), TO_RUBY_INT(row_count));
} 
/*******************************************************
 SQLFetch
 =======================================================
 PARAMS:   statement_handle : Integer
 RETURNS:  rc : Integer
********************************************************/
static VALUE
db2_SQLFetch(self, statement_handle)
  VALUE self;
  VALUE statement_handle;
{
  SQLRETURN rc;
  rc = SQLFetch(
    (SQLHSTMT) TO_C_INT(statement_handle)
  );
  return TO_RUBY_INT(rc); 
} 
/*******************************************************
 SQLFetchScroll
 =======================================================
 PARAMS:   statement_handle  : Integer,
           fetch_orientation : Integer,
           fetch_offset      : Integer 
 RETURNS:  rc : Integer
********************************************************/
static VALUE
db2_SQLFetchScroll(self, statement_handle, fetch_orientation, fetch_offset)
  VALUE self;
  VALUE statement_handle, fetch_orientation, fetch_offset;
{
  SQLRETURN rc;
  rc = SQLFetchScroll(
    (SQLHSTMT)    TO_C_INT(statement_handle),
    (SQLSMALLINT) TO_C_INT(fetch_orientation),
    (SQLINTEGER)  TO_C_INT(fetch_offset)
  );
  return TO_RUBY_INT(rc); 
} 
/*******************************************************
 SQLGetData
 =======================================================
 PARAMS:   statement_handle    : Integer, 
           column_number       : Integer,
           target_type         : Integer,    (e.g. SQL_BLOB)
           buffer_length = nil : Integer     (nil for e.g. SQL_INTEGER)
 RETURNS:  rc                  : Integer, 
           column              : ?, 
           strlen_or_indptr    :
********************************************************/
static VALUE
db2_SQLGetData(argc, argv, self)
  int argc;
  VALUE *argv;
  VALUE self;
{
  VALUE statement_handle, column_number, target_type, buffer_length;
  SQLRETURN  rc;
  SQLINTEGER strlen_or_indptr;
  SQLHSTMT sh;     /* statement_handle */
  SQLUSMALLINT cn; /* column_number    */
  SQLINTEGER bl;   /* buffer_length    */
  VALUE retval; 
  union {
    SQLDOUBLE        dbl;
    SQLREAL          real;
    SQLINTEGER       integer; 
    SQLSMALLINT      smallint;
    DATE_STRUCT      date;
    TIME_STRUCT      time;
    TIMESTAMP_STRUCT timestamp;
  } ptr_value;
  SQLPOINTER ptr;
  rb_scan_args(argc, argv, "31", &statement_handle, &column_number, 
               &target_type, &buffer_length);
               
  sh = TO_C_INT(statement_handle);
  cn = TO_C_INT(column_number);
  if (NIL_P(buffer_length) != 0) {
    bl = 0;
  } 
  else {
    bl = TO_C_INT(buffer_length);
  }
  #define CALL_SQL_GET_DATA(ptr, type, len)  \
    rc = SQLGetData(                         \
      (SQLHSTMT)     sh,                     \
      (SQLUSMALLINT) cn,                     \
      (SQLSMALLINT)  type,                   \
      (SQLPOINTER)   ptr,                    \
      (SQLINTEGER)   len,                    \
      (SQLINTEGER*)  &strlen_or_indptr       \
    );
  #define RETVAL(val)                                        \
    if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO)    \
      retval =                                               \
        (strlen_or_indptr == SQL_NULL_DATA) ? objNull : val; \
    else                                                     \
      retval = Qnil;                                         \
    
  switch (TO_C_INT(target_type)) {
    case SQL_DOUBLE:
    case SQL_FLOAT:
      CALL_SQL_GET_DATA(&ptr_value, SQL_C_DOUBLE, sizeof(SQLDOUBLE));  
      RETVAL( rb_float_new(ptr_value.dbl) );
      break;
    case SQL_REAL:
      CALL_SQL_GET_DATA(&ptr_value, SQL_C_FLOAT, sizeof(SQLREAL));  
      RETVAL( rb_float_new(ptr_value.real) );
      break;
    case SQL_INTEGER:
      CALL_SQL_GET_DATA(&ptr_value, SQL_C_LONG, sizeof(SQLINTEGER));  
      RETVAL( TO_RUBY_INT(ptr_value.integer) );
      break;
    case SQL_SMALLINT:
      CALL_SQL_GET_DATA(&ptr_value, SQL_C_SHORT, sizeof(SQLSMALLINT));  
      RETVAL( TO_RUBY_INT(ptr_value.smallint) );
      break;
    case SQL_TYPE_DATE:
      CALL_SQL_GET_DATA(&ptr_value, SQL_C_TYPE_DATE, sizeof(DATE_STRUCT));  
      RETVAL( rb_funcall( cDate, rb_intern("new"), 3, 
                          TO_RUBY_INT(ptr_value.date.year),
                          TO_RUBY_INT(ptr_value.date.month), 
                          TO_RUBY_INT(ptr_value.date.day) ) );
      break;
    case SQL_TYPE_TIME:
      CALL_SQL_GET_DATA(&ptr_value, SQL_C_TYPE_TIME, sizeof(TIME_STRUCT));  
      RETVAL( rb_funcall( cTime, rb_intern("new"), 3, 
                          TO_RUBY_INT(ptr_value.time.hour),
                          TO_RUBY_INT(ptr_value.time.minute), 
                          TO_RUBY_INT(ptr_value.time.second) ) );
      break;
    case SQL_TYPE_TIMESTAMP:
      CALL_SQL_GET_DATA(&ptr_value, SQL_C_TYPE_TIMESTAMP, sizeof(TIMESTAMP_STRUCT));  
      RETVAL( rb_funcall( cTimestamp, rb_intern("new"), 7, 
                          TO_RUBY_INT(ptr_value.timestamp.year),
                          TO_RUBY_INT(ptr_value.timestamp.month),
                          TO_RUBY_INT(ptr_value.timestamp.day),
                          TO_RUBY_INT(ptr_value.timestamp.hour),
                          TO_RUBY_INT(ptr_value.timestamp.minute), 
                          TO_RUBY_INT(ptr_value.timestamp.second), 
                          TO_RUBY_INT(ptr_value.timestamp.fraction) ) );
      break;
 
    case SQL_CHAR:
    case SQL_CLOB:
    case SQL_LONGVARCHAR:
    case SQL_VARCHAR:
    /* TODO: should handle SQL_DECIMAL and SQL_NUMERIC different ? */
    case SQL_DECIMAL:
    case SQL_NUMERIC:
    
      ptr = (SQLPOINTER) ALLOC_N(SQLCHAR, bl); 
      CALL_SQL_GET_DATA(ptr, SQL_C_CHAR, bl);  
      RETVAL( rb_str_new(ptr, MIN(bl, strlen_or_indptr)) );
  
      free((void*)ptr);
      break;
    
    case SQL_BLOB:
    case SQL_BINARY:
    case SQL_LONGVARBINARY:
    case SQL_VARBINARY:
      ptr = (SQLPOINTER) ALLOC_N(SQLCHAR, bl); 
      CALL_SQL_GET_DATA(ptr, SQL_C_BINARY, bl);  
      RETVAL( rb_str_new(ptr, MIN(bl, strlen_or_indptr)) );
  
      free((void*)ptr);
      break;
    case SQL_BLOB_LOCATOR:
      CALL_SQL_GET_DATA(&ptr_value, SQL_C_BLOB_LOCATOR, sizeof(SQLINTEGER));  
      RETVAL( TO_RUBY_INT(ptr_value.integer) );
      break;
    case SQL_CLOB_LOCATOR:
      CALL_SQL_GET_DATA(&ptr_value, SQL_C_CLOB_LOCATOR, sizeof(SQLINTEGER));  
      RETVAL( TO_RUBY_INT(ptr_value.integer) );
      break;
    case SQL_DBCLOB_LOCATOR:
      CALL_SQL_GET_DATA(&ptr_value, SQL_C_DBCLOB_LOCATOR, sizeof(SQLINTEGER));  
      RETVAL( TO_RUBY_INT(ptr_value.integer) );
      break;
    case SQL_BIGINT:
      /* TODO: How large can a BIGINT be? ==> expect 200 bytes, should be enought? */
      ptr = (SQLPOINTER) ALLOC_N(SQLCHAR, MAX(bl,200)); 
      CALL_SQL_GET_DATA(ptr, SQL_C_CHAR, bl);  
      RETVAL( rb_str_new(ptr, MIN(bl, strlen_or_indptr)) );
      rc = rb_funcall(rc, rb_intern("to_i"), 0); 
      free((void*)ptr);
      break;
    case SQL_DBCLOB:
    case SQL_GRAPHIC:
    case SQL_LONGVARGRAPHIC:
    case SQL_VARGRAPHIC:
      ptr = (SQLPOINTER) ALLOC_N(SQLCHAR, bl);  /* NOTE: not SQLDBCHAR */
      CALL_SQL_GET_DATA(ptr, SQL_C_DBCHAR, bl);  
      RETVAL( rb_str_new(ptr, MIN(bl, strlen_or_indptr)) );
  
      free((void*)ptr);
      break;
    default:
      rb_raise(rb_eTypeError, "Wrong parameter for target_type!");
  };
  #undef RETVAL
  #undef CALL_SQL_GET_DATA
  return rb_ary_new3(3, TO_RUBY_INT(rc), retval, TO_RUBY_INT(strlen_or_indptr));
} 
/*******************************************************
 SQLEndTran
 =======================================================
 PARAMS:   handle_type, handle, 
           completion_type : Integer
 RETURNS:  rc : Integer
********************************************************/
static VALUE
db2_SQLEndTran(self, handle_type, handle, completion_type)
  VALUE self;
  VALUE handle_type, handle, completion_type;
{
  SQLRETURN rc;
  rc = SQLEndTran(
    (SQLSMALLINT) TO_C_INT(handle_type),
    (SQLHANDLE)   TO_C_INT(handle),
    (SQLSMALLINT) TO_C_INT(completion_type) 
  );
  return TO_RUBY_INT(rc);  
} 
/*******************************************************
 SQLGetDiagRec
 =======================================================
 PARAMS:   handle_type, handle, rec_number,
           buffer_length : Integer
 RETURNS:  rc           : Integer, 
           sql_state    : String,
           native_error : Integer,
           message_text : String,
           text_length  : Integer
********************************************************/
static VALUE
db2_SQLGetDiagRec(self, handle_type, handle, rec_number, buffer_length)
  VALUE self;
  VALUE handle_type, handle, rec_number, buffer_length;
{
  SQLRETURN   rc;
  SQLCHAR     sql_state[5];
  SQLINTEGER  native_error;
  SQLCHAR*    message_text;
  SQLINTEGER  bl;           /* buffer_length */
  SQLSMALLINT text_length; 
  VALUE       retval;
  bl           = TO_C_INT(buffer_length);
  message_text = (SQLCHAR*) ALLOC_N(SQLCHAR, bl);
 
  rc = SQLGetDiagRec(
    (SQLSMALLINT)  TO_C_INT(handle_type),
    (SQLHANDLE)    TO_C_INT(handle),
    (SQLSMALLINT)  TO_C_INT(rec_number),
    (SQLCHAR*)     sql_state,
    (SQLINTEGER*)  &native_error,
    (SQLCHAR*)     message_text,
    (SQLINTEGER)   bl,
    (SQLSMALLINT*) &text_length
  );
  retval = rb_ary_new3(
    5, 
    TO_RUBY_INT(rc),
    rb_str_new(sql_state, 5),
    TO_RUBY_INT(native_error),
    rb_str_new(message_text, MIN(bl, text_length)),
    TO_RUBY_INT(text_length) 
  );
  free(message_text);
  
  return retval;
} 
/*******************************************************
 SQLTables
 =======================================================
 PARAMS:   statement_handle : Integer,
           catalog_name     : String,    (must be set to "")
           schema_name      : String,
           table_name       : String,
           table_type       : String     (e.g. "TABLE, VIEW")
 RETURNS:  rc : Integer
********************************************************/
static VALUE
db2_SQLTables(self, statement_handle, catalog_name, schema_name, 
              table_name, table_type)
  VALUE self;
  VALUE statement_handle, catalog_name, schema_name;
  VALUE table_name, table_type;
{
  SQLRETURN rc;
  MUST_BE_STRING(catalog_name);
  MUST_BE_STRING(schema_name);
  MUST_BE_STRING(table_name);
  MUST_BE_STRING(table_type);
  rc = SQLTables(
    (SQLHSTMT)     TO_C_INT(statement_handle),
    (SQLCHAR *FAR) RSTRING(catalog_name)->ptr,
    (SQLSMALLINT)  RSTRING(catalog_name)->len,
    (SQLCHAR *FAR) RSTRING(schema_name)->ptr,
    (SQLSMALLINT)  RSTRING(schema_name)->len,
    (SQLCHAR *FAR) RSTRING(table_name)->ptr,
    (SQLSMALLINT)  RSTRING(table_name)->len,
    (SQLCHAR *FAR) RSTRING(table_type)->ptr,
    (SQLSMALLINT)  RSTRING(table_type)->len
  );
  return TO_RUBY_INT(rc); 
} 
/* Init */
void Init_db2cli() {
  mDB2CLI = rb_eval_string("DB2CLI");
  #include "constants.h"
 
  rb_define_module_function(mDB2CLI, "SQLAllocHandle",   db2_SQLAllocHandle,   2); 
  rb_define_module_function(mDB2CLI, "SQLFreeHandle",    db2_SQLFreeHandle,    2); 
  rb_define_module_function(mDB2CLI, "SQLFreeStmt",      db2_SQLFreeStmt,      2); 
  rb_define_module_function(mDB2CLI, "SQLDataSources",   db2_SQLDataSources,   4); 
  rb_define_module_function(mDB2CLI, "SQLConnect",       db2_SQLConnect,       4); 
  rb_define_module_function(mDB2CLI, "SQLDisconnect",    db2_SQLDisconnect,    1); 
  rb_define_module_function(mDB2CLI, "SQLPrepare",       db2_SQLPrepare,       2); 
  rb_define_module_function(mDB2CLI, "SQLNumResultCols", db2_SQLNumResultCols, 1); 
  rb_define_module_function(mDB2CLI, "SQLDescribeCol",   db2_SQLDescribeCol,   3); 
  rb_define_module_function(mDB2CLI, "SQLColAttribute",  db2_SQLColAttribute,  4); 
  rb_define_module_function(mDB2CLI, "SQLExecDirect",    db2_SQLExecDirect,    2); 
  rb_define_module_function(mDB2CLI, "SQLExecute",       db2_SQLExecute,       1); 
  rb_define_module_function(mDB2CLI, "SQLRowCount",      db2_SQLRowCount,      1); 
  rb_define_module_function(mDB2CLI, "SQLFetch",         db2_SQLFetch,         1); 
  rb_define_module_function(mDB2CLI, "SQLFetchScroll",   db2_SQLFetchScroll,   3); 
  rb_define_module_function(mDB2CLI, "SQLGetData",       db2_SQLGetData,      -1); /* 3-4 */
  rb_define_module_function(mDB2CLI, "SQLEndTran",       db2_SQLEndTran,       3);
  rb_define_module_function(mDB2CLI, "SQLGetDiagRec",    db2_SQLGetDiagRec,    4);
  rb_define_module_function(mDB2CLI, "SQLTables",        db2_SQLTables,        5);
  /* Datatype classes or objects */
  cDate      = rb_eval_string("DB2CLI::Date");
  cTime      = rb_eval_string("DB2CLI::Time");
  cTimestamp = rb_eval_string("DB2CLI::Timestamp");
  objNull    = rb_eval_string("DB2CLI::Null");
}
--- NEW FILE: extconf.rb ---
require "mkmf"
if RUBY_PLATFORM =~ /(mswin32|cygwin|mingw)/
  # version 6.1 Windows 95/98/NT
  DB2LIB = "db2cli"   
  DB2DIR = ENV["DB2DIR"] || "C:/SQLLIB"
else
  # version 7.1 Linux 
  DB2LIB = "db2" 
  DB2DIR = ENV["DB2DIR"] || "/usr/IBMdb2/V7.1"
end
dir_config( "db2", DB2DIR + "/include", DB2DIR + "/lib" )
if have_library(DB2LIB, "SQLConnect") and 
   have_header("sqlcli.h")
  create_makefile "db2cli"
else
  puts "ABORT: Could not locate DB2 libraries or headers!"
  puts "Please set DB2DIR to your DB2 directory, e.g. /usr/IBMdb2/V7.1 (UNIX) " + 
       "or C:/SQLLIB (Windows)"
  exit 1
end
 |