ruby-db2-0.4/0040755000175100000000000000000007757751757012532 5ustar mneumannwheelruby-db2-0.4/ext/0040755000175100000000000000000007757751757013332 5ustar mneumannwheelruby-db2-0.4/ext/db2/0040755000175100000000000000000007757751757014001 5ustar mneumannwheelruby-db2-0.4/ext/db2/db2cli.c0100644000175100000000000010475407757747400015302 0ustar mneumannwheel/* * IBM DB2 CLI 5.0 (Call Level Interface) Module for Ruby * * File: db2cli.c * * Author: Michael Neumann (mneumann@ntecs.de) * * Contributors: * * Songsu Yun (yuns@us.ibm.com) * * Stephen R. Veit (sveit@tradeharbor.com) * * * Copyright (c) 2001, 2002, 2003 by Michael Neumann. * * Released under the same terms as Ruby itself. * * $Id: db2cli.c,v 1.5 2003/11/22 21:02:56 mneumann Exp $ * */ /********************************************************************** 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 #include #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); } /******************************************************* 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 ); if (rc != 0) { /* added by yun */ sn_length = 0; ds_length = 0; } /* Remove null-termination if it exists. Added by sveit. */ if (sn_length > 0 && server_name[sn_length - 1] == 0) sn_length--; if (ds_length > 0 && description[ds_length - 1] == 0) 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); } /******************************************************* SQLSetConnectAttr added by yun ======================================================= PARAMS: connection_handle : Integer, attribute: integer value: either string or integer RETURNS: rc : Integer NOTE: When passing a string as value, the string might have to be null-terminated. ********************************************************/ static VALUE db2_SQLSetConnectAttr(self, connection_handle, attribute, value) VALUE self; VALUE connection_handle, attribute, value; { SQLRETURN rc; if (TYPE(value) == T_STRING) { rc = SQLSetConnectAttr( (SQLHDBC) TO_C_INT(connection_handle), (SQLINTEGER) TO_C_INT(attribute), (SQLPOINTER) RSTRING(value)->ptr, (SQLINTEGER) RSTRING(value)->len ); } else { rc = SQLSetConnectAttr( (SQLHDBC) TO_C_INT(connection_handle), (SQLINTEGER) TO_C_INT(attribute), (SQLPOINTER) TO_C_INT(value), (SQLINTEGER) SQL_IS_INTEGER ); } 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)); } /******************************************************* SQLNumParams added by yun ======================================================= PARAMS: statement_handle : Integer RETURNS: rc, param_count : Integer ********************************************************/ static VALUE db2_SQLNumParams(self, statement_handle) VALUE self; VALUE statement_handle; { SQLRETURN rc; SQLSMALLINT param_count; rc = SQLNumParams( (SQLHSTMT) TO_C_INT(statement_handle), (SQLSMALLINT*) ¶m_count ); return rb_ary_new3(2, TO_RUBY_INT(rc), TO_RUBY_INT(param_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((const char *)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; } /******************************************************* SQLDescribeParam added by yun ======================================================= PARAMS: statement_handle : Integer, parameter_number : Integer, RETURNS: rc : Integer, parameter data type : Integer, parameter size : Integer, decimal_digits : Integer, nullable : Integer ********************************************************/ static VALUE db2_SQLDescribeParam(self, statement_handle, param_number) VALUE self; VALUE statement_handle, param_number; { SQLRETURN rc; SQLSMALLINT data_type, decimal_digits, nullable; SQLUINTEGER param_size; VALUE retval; rc = SQLDescribeParam( (SQLHSTMT) TO_C_INT(statement_handle), (SQLUSMALLINT) TO_C_INT(param_number), (SQLSMALLINT*) &data_type, (SQLUINTEGER*) ¶m_size, (SQLSMALLINT*) &decimal_digits, (SQLSMALLINT*) &nullable ); retval = rb_ary_new3( 5, TO_RUBY_INT(rc), TO_RUBY_INT(data_type), TO_RUBY_INT(param_size), TO_RUBY_INT(decimal_digits), TO_RUBY_INT(nullable) ); 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); } /******************************************************* SQLFreeStmt added by yun ======================================================= PARAMS: statement_handle : Integer option: option RETURNS: rc : Integer ********************************************************/ static VALUE db2_SQLFreeStmt(self, statement_handle, option) VALUE self; VALUE statement_handle; VALUE option; { SQLRETURN rc; rc = SQLFreeStmt( (SQLHSTMT) TO_C_INT(statement_handle), (SQLUSMALLINT) TO_C_INT(option) ); return TO_RUBY_INT(rc); } /******************************************************* SQLCloseCursor added by yun ======================================================= PARAMS: statement_handle : Integer RETURNS: rc : Integer ********************************************************/ static VALUE db2_SQLCloseCursor(self, statement_handle) VALUE self; VALUE statement_handle; { SQLRETURN rc; rc = SQLCloseCursor( (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 + 1); CALL_SQL_GET_DATA(ptr, SQL_C_CHAR, bl + 1); 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); if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO) { if (strlen_or_indptr == SQL_NULL_DATA) { retval = objNull; } else { /* convert string to integer */ retval = rb_str_new(ptr, MIN(bl, strlen_or_indptr)); retval = rb_funcall(retval, rb_intern("to_i"), 0); } } else { retval = Qnil; } 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((const char *)sql_state, 5), TO_RUBY_INT(native_error), rb_str_new((const char *)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); } /******************************************************* SQLBindParameter added by yun ======================================================= PARAMS: statement_handle : Integer, parameter_number : Integer, parameter_type : Integer, parameter_size : Integer, decimal_digits : Integer parameter_value : String, RETURNS: rc : Integer Note ValueType parameter to SQLBindParameter call is set to SQL_C_CHAR. DB2 will convert it to proper type based on ParameterType parameter(parameter_type) ********************************************************/ static VALUE db2_SQLBindParameter(self, statement_handle, parameter_number, parameter_type, parameter_size, decimal_digits, parameter_value) VALUE self; VALUE statement_handle, parameter_number, parameter_type, parameter_value; VALUE parameter_size, decimal_digits; { SQLRETURN rc; MUST_BE_STRING(parameter_value); rc = SQLBindParameter( (SQLHSTMT) TO_C_INT(statement_handle), (SQLUSMALLINT) TO_C_INT(parameter_number), (SQLSMALLINT) SQL_PARAM_INPUT, /* support input parameter only */ (SQLSMALLINT) SQL_C_CHAR, /* ValueType. Always string */ (SQLSMALLINT) TO_C_INT(parameter_type), /* SQL data type of the parameter */ (SQLUINTEGER) TO_C_INT(parameter_size), /* column size */ (SQLSMALLINT) TO_C_INT(decimal_digits), /* decimal digits */ (SQLCHAR *FAR) RSTRING(parameter_value)->ptr, /* parameter value pointer */ (SQLINTEGER) RSTRING(parameter_value)->len, /* buffer length */ (SQLINTEGER *FAR) &(RSTRING(parameter_value)->len) /*StrLen */ ); return TO_RUBY_INT(rc); } /******************************************************* SQLGetCursorName added by yun ======================================================= PARAMS: statement_handle : Integer, RETURNS: rc : Integer ********************************************************/ static VALUE db2_SQLGetCursorName(self, statement_handle) VALUE self; VALUE statement_handle; { SQLRETURN rc; char name[20]; short length; VALUE retval; rc = SQLGetCursorName( (SQLHSTMT) TO_C_INT(statement_handle), (SQLCHAR *FAR) name, (SQLSMALLINT) 18, (SQLSMALLINT *) &length ); retval = rb_ary_new3( 2, TO_RUBY_INT(rc), rb_str_new((const char *)name, length) ); return retval; } /******************************************************* SQLSetCursorName added by yun ======================================================= PARAMS: statement_handle : Integer, name : String RETURNS: rc : Integer ********************************************************/ static VALUE db2_SQLSetCursorName(self, statement_handle, name) VALUE self; VALUE statement_handle, name; { SQLRETURN rc; MUST_BE_STRING(name); rc = SQLSetCursorName( (SQLHSTMT) TO_C_INT(statement_handle), (SQLCHAR *FAR) RSTRING(name)->ptr, (SQLSMALLINT) RSTRING(name)->len ); return TO_RUBY_INT(rc); } /******************************************************* SQLColumns ======================================================= PARAMS: statement_handle : Integer, catalog_name : String, (must be set to "") schema_name : String, table_name : String, column_name : String RETURNS: rc : Integer ********************************************************/ static VALUE db2_SQLColumns(self, statement_handle, catalog_name, schema_name, table_name, column_name) VALUE self; VALUE statement_handle, catalog_name, schema_name; VALUE table_name, column_name; { SQLRETURN rc; MUST_BE_STRING(catalog_name); MUST_BE_STRING(schema_name); MUST_BE_STRING(table_name); MUST_BE_STRING(column_name); rc = SQLColumns( (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(column_name)->ptr, (SQLSMALLINT) RSTRING(column_name)->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, "SQLDataSources", db2_SQLDataSources, 4); rb_define_module_function(mDB2CLI, "SQLConnect", db2_SQLConnect, 4); rb_define_module_function(mDB2CLI, "SQLSetConnectAttr",db2_SQLSetConnectAttr,3); 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, "SQLNumParams", db2_SQLNumParams, 1); rb_define_module_function(mDB2CLI, "SQLDescribeCol", db2_SQLDescribeCol, 3); rb_define_module_function(mDB2CLI, "SQLDescribeParam", db2_SQLDescribeParam, 2); 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, "SQLCloseCursor", db2_SQLCloseCursor, 1); rb_define_module_function(mDB2CLI, "SQLFreeStmt", db2_SQLFreeStmt, 2); 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); rb_define_module_function(mDB2CLI, "SQLColumns", db2_SQLColumns, 5); rb_define_module_function(mDB2CLI, "SQLBindParameter", db2_SQLBindParameter, 6); rb_define_module_function(mDB2CLI, "SQLSetCursorName", db2_SQLSetCursorName, 2); rb_define_module_function(mDB2CLI, "SQLGetCursorName", db2_SQLGetCursorName, 1); /* 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"); } ruby-db2-0.4/ext/db2/constants.h0100644000175100000000000001513007730113120016122 0ustar mneumannwheelrb_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)); rb_define_const(mDB2CLI, "SQL_WLONGVARCHAR", INT2NUM(SQL_WLONGVARCHAR)); rb_define_const(mDB2CLI, "SQL_TINYINT", INT2NUM(SQL_TINYINT)); rb_define_const(mDB2CLI, "SQL_BIT", INT2NUM(SQL_BIT)); rb_define_const(mDB2CLI, "SQL_WVARCHAR", INT2NUM(SQL_WVARCHAR)); rb_define_const(mDB2CLI, "SQL_DATALINK", INT2NUM(SQL_DATALINK)); rb_define_const(mDB2CLI, "SQL_WCHAR", INT2NUM(SQL_WCHAR)); ruby-db2-0.4/ext/db2/extconf.rb0100644000175100000000000000113407535625171015750 0ustar mneumannwheelrequire "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 ruby-db2-0.4/ext/PATHCONV0100644000175100000000000000001407535625171014447 0ustar mneumannwheeldb2 db2 db2 ruby-db2-0.4/lib/0040755000175100000000000000000007757751757013300 5ustar mneumannwheelruby-db2-0.4/lib/db2/0040755000175100000000000000000007757751757013747 5ustar mneumannwheelruby-db2-0.4/lib/db2/db2cli.rb0100644000175100000000000000214507535625171015412 0ustar mneumannwheel# # $Id: db2cli.rb,v 1.1 2002/09/05 09:57:13 mneumann Exp $ # require "singleton" module DB2CLI class Date attr_accessor :year, :month, :day def initialize(year=0, month=0, day=0) @year, @month, @day = year, month, day end def to_s "#{@year}-#{@month}-#{@day}" end end class Time attr_accessor :hour, :minute, :second def initialize(hour=0, minute=0, second=0) @hour, @minute, @second = hour, minute, second end def to_s "#{@hour}:#{@minute}:#{@second}" end end class Timestamp attr_accessor :year, :month, :day attr_accessor :hour, :minute, :second, :fraction def initialize(year=0, month=0, day=0, hour=0, minute=0, second=0, fraction=0) @year, @month, @day = year, month, day @hour, @minute, @second, @fraction = hour, minute, second, fraction end def to_s "#{@year}-#{@month}-#{@day} #{@hour}:#{@minute}:#{@second}.#{@fraction}" end end class NullClass include Singleton def to_s "NULL" end end Null = NullClass.instance end # module DB2CLI require "db2/db2cli.so" ruby-db2-0.4/lib/PATHCONV0100644000175100000000000000001407535625171014415 0ustar mneumannwheeldb2 db2 db2 ruby-db2-0.4/ChangeLog0100644000175100000000000000225407757751615014275 0ustar mneumannwheel=begin = ChangeLog for Ruby/DB2 : 0.4 * fixed bug in db2_SQLGetData, that caused the last character of a SQL_CHAR column to be null (S. Veit) * fixes bug in SQLGetData that occurs for SQL_BIGINTs (S. Veit) * db2_SQLDataSources: remove null-termination if it exists (by S. Veit) * SQLColumns method added (by S. Veit) * Some SQL_XXX constants added (by S. Veit) : 0.3 * sqlsh.rb interactive SQL shell * Added CLI-functions: SQLFreeStmt : 0.2 * DBD driver for DB2 is available (show RAA under DBD/DB2) * added more examples * added README * Load path for require now prefixed by db2/ * Changed directory layout and using setup.rb * Added following CLI-functions: SQLDataSources, SQLColAttribute, SQLFetchScroll, SQLTables * Now all datatypes in SQLGetData can be handled. : 0.1 * Only the following CLI-functions are implemented: SQLAllocHandle, SQLFreeHandle, SQLConnect, SQLDisconnect, SQLPrepare, SQLNumResultCols, SQLDescribeCol, SQLExecDirect, SQLExecute, SQLRowCount, SQLFetch, SQLGetData, SQLEndTran, SQLGetDiagRec. * No high-level interface! * Tested with DB2 7.1 on Suse Linux 6.3. = History $Id: ChangeLog,v 1.3 2003/11/22 21:22:21 mneumann Exp $ =end ruby-db2-0.4/Makefile0100644000175100000000000000063707535625171014155 0ustar mneumannwheel export: clean mkdir -p work (cd work; cvs export -D now ruby/ruby-db2) (cd work/ruby/ruby-db2; rm -rf utils Makefile) clean: rm -rf work pack: mkdir -p work/pack ( cd work/pack; cvs export -r Release-$(TAG_MAJOR)_$(TAG_MINOR) ruby/ruby-db2; \ cd ruby/ruby-db2; rm -rf utils Makefile; \ cd ..; tar -cvzf ruby-db2-$(TAG_MAJOR).$(TAG_MINOR).tar.gz ruby-db2 ) ruby-db2-0.4/README0100644000175100000000000000330207535625171013365 0ustar mneumannwheel$Id: README,v 1.1 2002/09/05 09:57:13 mneumann Exp $ Ruby/DB2: IBM DB2 Module for Ruby Copyright (C) 2001 by Michael Neumann (neumann@s-direktnet.de) Released under the same terms as Ruby itself. PREREQUISITES ============= * IBM DB2 installed (with CLI), tested with DB2 V7.1 on Suse Linxu 6.3 and DB2 UDB V6.1 for Windows 95/98/NT. * Ruby, only tested with Ruby 1.6.3, but should work with every version >= 1.6. * C-Compiler INSTALL ======= To compile type the following: ruby setup.rb config ruby setup.rb setup If you get an error message that no libraries and header files were found, then you have to set DB2DIR to the correct path where DB2 was installed, e.g.: export DB2DIR=/usr/IBMdb2/V7.1 or under Cygwin and DB2 installed in C:\SQLLIB: export DB2DIR=C:/SQLLIB To install, make sure you are the superuser (under UNIX type "su -l root") and then type: ruby setup.rb install For more options on installation, type: ruby setup.rb --help The DB2 library files are installed in your site_ruby directory, of the actual ruby-version (e.g. "site_ruby/1.6") under the directory "db2" and the .so file under "$arch/db2", where $arch is your architecure (e.g. i686-linux). DOCUMENTATION ============= Not yet written. You should consult the DB2-CLI manual available from IBM's website and look at the comments before each function in the file "ext/db2/db2cli.c". The rule of thumb is that all parameters in the DB2-CLI manual which are declared as "output" or "input/output" are returned by the function (in an array). All input values which are of type HANDLE (HENV, HDBC, HSTMT...) are represented by Integer parameters in the Ruby version. SAMPLES ======= See directory "samples". ruby-db2-0.4/setup.rb0100644000175100000000000003553007730112722014170 0ustar mneumannwheel# # setup.rb # # Copyright (c) 2000,2001 Minero Aoki # # This program is free software. # You can distribute/modify this program under the terms of # the GNU General Public License version 2 or later. # require 'tempfile' if i = ARGV.index(/\A--rbconfig=/) then file = $' ARGV.delete_at(i) require file else require 'rbconfig' end class InstallError < StandardError; end class Installer Version = '2.0.4' Copyright = 'Copyright (c) 2000,2001 Minero Aoki' TASKS = { 'config' => 'save your config configurations', 'setup' => 'compiles extention or else', 'install' => 'installs packages', 'clean' => "does `make clean' for each extention", 'dryrun' => 'does test run', 'show' => 'shows current configuration' } TASK_ORDER = %w( config setup install clean dryrun show ) FILETYPES = %w( bin lib ext share ) def initialize( argv ) argv = argv.dup @verbose = true @no_harm = false @config = {} @task = nil @other_args = [] @task = parsearg( argv ) parsearg_TASK @task, argv unless @task == 'config' then load_configs check_packdesig end end attr :config attr :task ### ### arg proc. ### def parsearg( argv ) task_re = /\A(?:#{TASKS.keys.join '|'})\z/ task = nil arg = argv.shift case arg when /\A\w+\z/ unless task_re === arg then raise InstallError, "wrong task: #{arg}" end task = arg when '-h', '--help' print_usage $stdout exit 0 when '-v', '--version' puts "setup.rb version #{Version}" exit 0 when '--copyright' puts Copyright exit 0 else raise InstallError, "unknown global option '#{arg}'" end task end def parsearg_TASK( task, argv ) mid = "parsearg_#{task}" if respond_to? mid, true then __send__ mid, argv else unless argv.empty? then raise InstallError, "#{task}: unknown options: #{argv.join ' '}" end end end def parsearg_config( args ) @config_args = {} re = /\A--(#{CONFIG_ORDER.join '|'})=/ args.each do |i| m = re.match(i) or raise InstallError, "config: unknown option #{i}" @config_args[ m[1] ] = m.post_match.strip end end def parsearg_install( args ) args.each do |i| if i == '--no-harm' then @no_harm = true else raise InstallError, "#{@task}: wrong option #{i}" end end end def parsearg_dryrun( args ) @dryrun_args = args end def print_usage( out ) out.puts out.puts 'Usage:' out.puts ' ruby setup.rb ' out.puts ' ruby setup.rb []' out.puts out.puts 'Tasks:' TASK_ORDER.each do |name| out.printf " %-10s %s\n", name, TASKS[name] end fmt = " %-20s %s\n" out.puts out.puts 'Global options:' out.printf fmt, '-h,--help', 'print this message' out.printf fmt, '-v,--version', 'print version' out.printf fmt, '--copyright', 'print copyright' out.puts out.puts 'Options for config:' CONFIG_ORDER.each do |name| dflt, arg, desc, dflt2 = CONFIG_OPTS[name] dflt = dflt2 || dflt out.printf " %-20s %s [%s]\n", "--#{name}=#{arg}", desc, dflt end out.printf " %-20s %s [%s]\n", '--rbconfig=path', 'your rbconfig.rb to load', "running ruby's" out.puts out.puts 'Options for install:' out.printf " %-20s %s [%s]\n", '--no-harm', 'only display what to do if given', 'off' out.puts out.puts 'This archive includes:' out.print ' ', packages().join(' '), "\n" out.puts end ### ### tasks ### def execute case @task when 'config', 'setup', 'install', 'clean' tryto @task when 'show' do_show when 'dryrun' do_dryrun else raise 'must not happen' end end def tryto( task ) $stderr.printf "entering %s phase...\n", task begin __send__ 'do_' + task rescue $stderr.printf "%s failed\n", task raise end $stderr.printf "%s done.\n", task end ConfigFile = 'config.save' def do_config CONFIG_OPTS.each do |k,v| dflt, vname, desc = v @config[k] = dflt end @config_args.each do |k,v| setconf k, v end save_configs end def do_show CONFIG_ORDER.each do |k| v = @config[k] if not v or v.empty? then v = '(not specified)' end printf "%-10s %s\n", k, v end end def do_setup into_dir( 'bin' ) { foreach_package do Dir.foreach( '.' ) do |fname| next unless File.file? fname add_rubypath fname end end } into_dir( 'ext' ) { foreach_package do clean extconf make end } end def do_install into_dir( 'bin' ) { foreach_package do |targ, *dummy| install_bin end } into_dir( 'lib' ) { foreach_package do |targ, topfile| install_rb targ if topfile then create_topfile targ, topfile end end } into_dir( 'ext' ) { foreach_package do |targ, *dummy| install_so targ end } into_dir( 'share' ) { foreach_package do |targ, *dummy| install_dat targ end } end def do_clean into_dir( 'ext' ) { foreach_package do clean end } # rmf ConfigFile end def do_dryrun unless dir? 'tmp' then $stderr.puts 'setup.rb: setting up temporaly environment...' @verbose = $DEBUG begin @config['bin-dir'] = isdir(File.expand_path('.'), 'tmp', 'bin') @config['rb-dir'] = isdir(File.expand_path('.'), 'tmp', 'lib') @config['so-dir'] = isdir(File.expand_path('.'), 'tmp', 'ext') @config['data-dir'] = isdir(File.expand_path('.'), 'tmp', 'share') do_install rescue rmrf 'tmp' $stderr.puts '[BUG] setup.rb bug: "dryrun" command failed' raise end end exec @config['ruby-path'], '-I' + File.join('.', 'tmp', 'lib'), '-I' + File.join('.', 'tmp', 'ext'), *@dryrun_args end ### ### lib ### # # config # c = ::Config::CONFIG rubyname = c['ruby_install_name'] major = c['MAJOR'].to_i minor = c['MINOR'].to_i teeny = c['TEENY'].to_i version = "#{major}.#{minor}" arch = c['arch'] bindir = File.join( c['bindir'] ) rubylib = File.join( c['libdir'], 'ruby' ) datadir = File.join( c['datadir'] ) rubypath = File.join( bindir, rubyname ) # >=1.4.4 is new path newpath_p = ((major >= 2) or ((major == 1) and ((minor >= 5) or ((minor == 4) and (teeny >= 4))))) if newpath_p then sitelibdir = File.join( rubylib, 'site_ruby', version ) else sitelibdir = File.join( rubylib, version, 'site_ruby' ) end stdlibdir = File.join( rubylib, version ) siterb = sitelibdir siteso = File.join( sitelibdir, arch ) CONFIG_OPTS = { 'bin-dir' => [ bindir, 'path', 'directory to install commands' ], 'rb-dir' => [ siterb, 'path', 'directory to install ruby scripts' ], 'so-dir' => [ siteso, 'path', 'directory to install ruby extentions' ], 'data-dir' => [ datadir, 'path', 'directory to install data' ], 'ruby-path' => [ rubypath, 'path', 'path to ruby for #!' ], 'ruby-prog' => [ rubypath, 'path', 'path to ruby for installation' ], 'make-prog' => [ 'make', 'name', 'make program to compile ruby extentions' ], 'with' => [ '', 'name,name...', 'package name(s) you want to install', 'ALL' ], 'without' => [ '', 'name,name...', 'package name(s) you do not want to install' ] } CONFIG_ORDER = %w( bin-dir rb-dir so-dir ruby-path make-prog with without ) def save_configs File.open( ConfigFile, 'w' ) do |f| @config.each do |k,v| f.printf "%s=%s\n", k, v if v end end end def load_configs File.file? ConfigFile or raise InstallError, 'setup.rb config first' File.foreach( ConfigFile ) do |line| k, v = line.split( '=', 2 ) setconf k.strip, v.strip end end def setconf( k, v ) if CONFIG_OPTS[k][1] == 'path' then @config[k] = File.expand_path(v) else @config[k] = v end end # # packages # def check_packdesig @with = extract_dirs( @config['with'] ) @without = extract_dirs( @config['without'] ) packs = packages (@with + @without).each do |i| if not packs.include? i and not dir? i then raise InstallError, "no such package or directory '#{i}'" end end end def extract_dirs( s ) ret = [] s.split(',').each do |i| if /[\*\?]/ === i then tmp = Dir.glob(i) tmp.delete_if {|d| not dir? d } if tmp.empty? then tmp.push i # causes error else ret.concat tmp end else ret.push i end end ret end def packages ret = [] FILETYPES.each do |type| next unless File.exist? type foreach_record( "#{type}/PATHCONV" ) do |dir, pack, *dummy| ret.push pack end end ret.uniq end def foreach_package path = {} foreach_record( './PATHCONV' ) do |dir, pack, targ, topfile, *dummy| path[dir] = [pack, targ, topfile] end base = File.basename( Dir.getwd ) Dir.foreach('.') do |dir| next if dir[0] == ?. next unless dir? dir path[dir] or raise "abs path for package '#{dir}' not exist" pack, targ, topfile = path[dir] if inclpack pack, "#{base}/#{dir}" then chdir( dir ) { yield targ, topfile } else $stderr.puts "setup.rb: skip #{base}/#{dir}(#{pack}) by user option" end end end def foreach_record( fname ) File.foreach( fname ) do |line| line.strip! next if line.empty? a = line.split(/\s+/) a[2] ||= '.' yield a end end def inclpack( pack, dname ) if @with.empty? then not @without.include? pack and not @without.include? dname else @with.include? pack or @with.include? dname end end # # setup # def add_rubypath( fn, opt = nil ) line = "\#!#{@config['ruby-path']}#{opt ? ' ' + opt : ''}" $stderr.puts %Q if @verbose return if @no_harm tmpf = nil File.open( fn ) do |f| first = f.gets return unless /\A\#!.*ruby/ === first tmpf = Tempfile.open( 'amsetup' ) tmpf.puts line tmpf << first f.each {|i| tmpf << i } tmpf.close end mod = File.stat( fn ).mode tmpf.open File.open( fn, 'w' ) do |wf| tmpf.each {|i| wf << i } end File.chmod mod, fn tmpf.close true end # # install # def install_bin install_all isdir(@config['bin-dir']), 0555 end def install_rb( dir ) install_all isdir(@config['rb-dir'] + '/' + dir), 0644 end def install_dat( dir ) install_all isdir(@config['data-dir'] + '/' + dir), 0644 end def install_all( dir, mode ) Dir.foreach('.') do |fname| next if /\A\./ === fname next unless File.file? fname install fname, dir, mode end end def create_topfile( name, req ) d = isdir(@config['rb-dir']) File.open( "#{d}/#{name}.rb", 'w' ) do |f| f.puts "require '#{name}/#{req}'" end File.chmod 0644, "#{d}/#{name}.rb" end def extconf command "#{@config['ruby-prog']} extconf.rb" end def make command @config['make-prog'] end def clean command @config['make-prog'] + ' clean' if File.file? 'Makefile' end def install_so( dir ) to = isdir(File.expand_path(@config['so-dir'] + '/' + dir)) find_so('.').each do |fn| install fn, to, 0555 end end DLEXT = ::Config::CONFIG['DLEXT'] def find_so( dir = '.' ) fnames = nil Dir.open( dir ) {|d| fnames = d.to_a } exp = /\.#{DLEXT}\z/ arr = fnames.find_all {|fn| exp === fn } arr or raise InstallError, 'no ruby extention exists: have you done "ruby setup.rb setup" ?' end def so_dir?( dn = '.' ) File.file? "#{dn}/MANIFEST" end # # file op. # def into_dir( libn ) return unless dir? libn chdir( libn ) { yield } end def chdir( dn ) curr = Dir.pwd begin Dir.chdir dn yield ensure Dir.chdir curr end end def isdir( dn ) mkpath dn dn end def mkpath( dname ) $stderr.puts "mkdir -p #{dname}" if @verbose return if @no_harm # does not check '/'... it's too abnormal case dirs = dname.split(%r_(?=/)_) if /\A[a-z]:\z/i === dirs[0] then disk = dirs.shift dirs[0] = disk + dirs[0] end dirs.each_index do |idx| path = dirs[0..idx].join('') Dir.mkdir path unless dir? path end end def rmf( fname ) $stderr.puts "rm -f #{fname}" if @verbose return if @no_harm if File.exist? fname or File.symlink? fname then File.chmod 777, fname File.unlink fname end end def rmrf( dn ) $stderr.puts "rm -rf #{dn}" if @verbose return if @no_harm Dir.chdir dn Dir.foreach('.') do |fn| next if fn == '.' next if fn == '..' if dir? fn then verbose_off { rmrf fn } else verbose_off { rmf fn } end end Dir.chdir '..' Dir.rmdir dn end def verbose_off save, @verbose = @verbose, false yield @verbose = save end def install( from, to, mode ) $stderr.puts "install #{from} #{to}" if @verbose return if @no_harm if dir? to then to = to + '/' + File.basename(from) end str = nil File.open( from, 'rb' ) {|f| str = f.read } if diff? str, to then verbose_off { rmf to if File.exist? to } File.open( to, 'wb' ) {|f| f.write str } File.chmod mode, to end end def diff?( orig, comp ) return true unless File.exist? comp s2 = nil File.open( comp, 'rb' ) {|f| s2 = f.read } orig != s2 end def command( str ) $stderr.puts str if @verbose system str or raise RuntimeError, "'system #{str}' failed" end def dir?( dname ) # for CORRUPTED windows stat() File.directory? (dname[-1,1] == '/' ? dname : dname + '/') end end if $0 == __FILE__ then begin MainInstaller = Installer.new( ARGV ) MainInstaller.execute rescue raise if $DEBUG $stderr.puts $! $stderr.puts 'try "ruby setup.rb --help" for usage' exit 1 end end ruby-db2-0.4/samples/0040755000175100000000000000000007757751757014176 5ustar mneumannwheelruby-db2-0.4/samples/sqlsh.rb0100644000175100000000000000557307535625172015645 0ustar mneumannwheel require "readline" require "db2" class ReadlineControl def initialize @keywords = [] set_prompt Readline.completion_proc = proc {|str| complete(str) } end def add_keywords(arr) @keywords += arr end def complete(str) @keywords.grep(/^#{Regexp.escape(str)}/i) end def set_prompt(prompt="> ") @prompt = prompt end def readline Readline.readline(@prompt, true) end end if ARGV.size < 1 or ARGV.size > 3 puts puts "USAGE: #{$0} database [, user [, password] ]" puts exit 1 else DB = ARGV.shift USER = ARGV.shift || "" PASS = ARGV.shift || "" end puts begin print " CONNECT TO #{DB}" print " USER '#{USER}'" unless USER.empty? print " PASSWORD '#{PASS}'" unless PASS.empty? puts Env = DB2::Environment.new Conn = Env.createConnection("SAMPLE") rescue DB2::CLIError => err puts puts err.message puts end puts PROMPT = "db2 => " PROMPT_CONT = "db2 =| " SQL_KEYWORDS = %w( INSERT DELETE UPDATE SELECT FROM WHERE IN LIKE SET VALUES INTO CREATE TABLE DROP COMMIT ROLLBACK CHAR VARCHAR INT INTEGER NUMBER FLOAT REAL LONG CLOB BLOB DECIMAL DBCLOB DBBLOB ) rd = ReadlineControl.new rd.add_keywords SQL_KEYWORDS rd.set_prompt(PROMPT) def output_table(rows) collength = [] rows.each {|r| r.each_with_index {|c,i| r[i] = c.to_s.chomp("\000") c = r[i] collength[i] = c.size if collength[i].nil? or c.size > collength[i] } } split_line = " +" collength.each {|col| split_line << "-" * (col+2) + "+" } puts puts split_line # output table rows.each_with_index {|r, rn| print " |" r.each_with_index {|c,i| print sprintf(" %*2$s |", c.to_s, -(collength[i])) } puts puts split_line if rn == 0 } puts split_line puts end loop { line = rd.readline line.chomp! next if line.empty? begin if line =~ /^\\/ then if line =~ /^\\list tables/i then stmt = Conn.createStatement.tables elsif line =~ /^\\list views/i then stmt = Conn.createStatement.tables("%", "%", "VIEW") elsif line =~ /^\\quit/i then break else puts puts "Unknown command!" puts next end else # multi-line if line[-1].chr == "\\" then line.chop! rd.set_prompt(PROMPT_CONT) loop { ln = rd.readline line.chomp! next if line.empty? if ln[-1].chr == "\\" then line += ln.chop else line += ln break end } end rd.set_prompt(PROMPT) stmt = Conn.createStatement.execDirect(line) end head = stmt.colNames next if head.empty? rows = stmt.fetchAll rows[0,0] = [head] output_table(rows) rescue DB2::CLIError => err puts puts err.message puts end } Conn.disconnect Conn.free Env.free ruby-db2-0.4/samples/db2.rb0100644000175100000000000002526007600565743015155 0ustar mneumannwheel require "db2/db2cli.rb" module DB2 module DB2Util include DB2CLI def free SQLFreeHandle(@handle_type, @handle) end def handle @handle end def check_rc(rc) if rc != SQL_SUCCESS and rc != SQL_SUCCESS_WITH_INFO case rc when SQL_NEED_DATA rcText = 'SQL_NEED_DATA' when SQL_NO_DATA_FOUND rcText = 'SQL_NO_DATA' when SQL_STILL_EXECUTING rcText = 'SQL_STILL_EXECUTING' when SQL_ERROR rcText = 'SQL_ERROR' when SQL_INVALID_HANDLE rcText = 'SQL_INVALID_HANDLE' end puts "DB2 return code is #{rcText}" rec = 1 loop do a = SQLGetDiagRec(@handle_type, @handle, rec, 500) break if a[0] != SQL_SUCCESS puts a[3] if a[3] != nil and a[3] != '' #display message rec += 1 end raise "ERROR From DB2" end end end # module DB2Util class Environment include DB2Util def initialize @handle_type = SQL_HANDLE_ENV rc, @handle = SQLAllocHandle(@handle_type, SQL_NULL_HANDLE) check_rc(rc) end def data_sources(buffer_length = 1024) retval = [] max_buffer_length = buffer_length a = SQLDataSources(@handle, SQL_FETCH_FIRST, SQL_MAX_DSN_LENGTH+1, buffer_length) retval << [a[1], a[3]] max_buffer_length = [max_buffer_length, a[4]].max loop do a = SQLDataSources(@handle, SQL_FETCH_NEXT, SQL_MAX_DSN_LENGTH+1, buffer_length) break if a[0] == SQL_NO_DATA_FOUND retval << [a[1], a[3]] max_buffer_length = [max_buffer_length, a[4]].max end if max_buffer_length > buffer_length then get_data_sources(max_buffer_length) else retval end end end # class Environment class Connection include DB2Util def initialize(environment) @env = environment @handle_type = SQL_HANDLE_DBC rc, @handle = SQLAllocHandle(@handle_type, @env.handle) check_rc(rc) end def connect(server_name, user_name="", auth="") rc = SQLConnect(@handle, server_name, user_name, auth) check_rc(rc) end def set_auto_commit(switch) switch.upcase! if switch != 'ON' and switch != 'OFF' raise 'set_auto_commit: Specify either "ON" or "OFF"' end if switch == 'ON' rc = SQLSetConnectAttr(@handle, SQL_ATTR_AUTOCOMMIT, SQL_AUTOCOMMIT_ON) else rc = SQLSetConnectAttr(@handle, SQL_ATTR_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF) end check_rc(rc) end def set_connect_attr(attr, value) if value.type == String value += "\0" end rc = SQLSetConnectAttr(@handle, attr, value) check_rc(rc) end def disconnect rc = SQLDisconnect(@handle) check_rc(rc) end def rollback rc = SQLEndTran(@handle_type, @handle, SQL_ROLLBACK) check_rc(rc) end def commit rc = SQLEndTran(@handle_type, @handle, SQL_COMMIT) check_rc(rc) end end # class Connection class Statement include DB2Util def initialize(connection) @conn = connection @handle_type = SQL_HANDLE_STMT @parms = [] #yun @sql = '' #yun @numParms = 0 #yun @prepared = false #yun @parmArray = [] #yun. attributes of the parameter markers rc, @handle = SQLAllocHandle(@handle_type, @conn.handle) check_rc(rc) end def prepare(sql) @sql = sql rc = SQLPrepare(@handle, sql) check_rc(rc) rc, @numParms = SQLNumParams(@handle) #number of question marks check_rc(rc) #-------------------------------------------------------------------------- # parameter attributes are stored in instance variable @parmArray so that # they are available when execute method is called. #-------------------------------------------------------------------------- if @numParms > 0 #get parameter marker attributes 1.upto(@numParms) do #parameter number starts from 1 | i | rc, type, size, decimalDigits = SQLDescribeParam(@handle, i) check_rc(rc) @parmArray << Parameter.new(type, size, decimalDigits) end end @prepared = true; self end def execute(*parms) if @prepared == false raise "The statement was not prepared" end if parms.size == 1 and parms[0].type == Array parms = parms[0] end if (@numParms != parms.size) raise "Number of parameters supplied does not match with the SQL statement" end if @numParms > 0 #need to bind parameters #-------------------------------------------------------------------- #calling bindParms may not be safe. Look comment below. #-------------------------------------------------------------------- #bindParms(parms) #may not be safe valueArray = [] 1.upto(@numParms) do #parameter number starts from 1 | i | type = @parmArray[i - 1].type size = @parmArray[i - 1].size decimalDigits = @parmArray[i - 1].decimalDigits if parms[i - 1].type == String valueArray << parms[i - 1] else valueArray << parms[i - 1].to_s end rc = SQLBindParameter(@handle, i, type, size, decimalDigits, valueArray[i - 1]) check_rc(rc) end end rc = SQLExecute(@handle) check_rc(rc) if @numParms != 0 SQLFreeStmt(@handle, SQL_RESET_PARAMS) #reset parameters check_rc(rc) end self end #------------------------------------------------------------------------------- # The last argument(value) to SQLBindParameter is a deferred argument, that is, # it should be available when SQLExecute is called. Even though "value" is # local to bindParms method, it seems that it is available when SQLExecute # is called. I am not sure whether it would still work if garbage collection # is done between bindParms call and SQLExecute call inside the execute method # above. #------------------------------------------------------------------------------- def bindParms(parms) #This is the real thing. It uses SQLBindParms 1.upto(@numParms) do #parameter number starts from 1 | i | rc, dataType, parmSize, decimalDigits = SQLDescribeParam(@handle, i) check_rc(rc) if parms[i - 1].type == String value = parms[i - 1] else value = parms[i - 1].to_s end rc = SQLBindParameter(@handle, i, dataType, parmSize, decimalDigits, value) check_rc(rc) end end #------------------------------------------------------------------------------ # bind method does not use DB2's SQLBindParams, but replaces "?" in the # SQL statement with the value before passing the SQL statement to DB2. # It is not efficient and can handle only strings since it puts everything in # quotes. #------------------------------------------------------------------------------ def bind(sql, args) #does not use SQLBindParams arg_index = 0 result = "" tokens(sql).each { |part| case part when '?' result << "'" + (args[arg_index]) + "'" #put it into quotes arg_index += 1 when '??' result << "?" else result << part end } if arg_index < args.size raise "Too many SQL parameters" elsif arg_index > args.size raise "Not enough SQL parameters" end result end ## Break the sql string into parts. # # This is NOT a full lexer for SQL. It just breaks up the SQL # string enough so that question marks, double question marks and # quoted strings are separated. This is used when binding # arguments to "?" in the SQL string. Note: comments are not # handled. # def tokens(sql) toks = sql.scan(/('([^'\\]|''|\\.)*'|"([^"\\]|""|\\.)*"|\?\??|[^'"?]+)/) toks.collect {|t| t[0]} end def exec_direct(sql) rc = SQLExecDirect(@handle, sql) check_rc(rc) self end def set_cursor_name(name) rc = SQLSetCursorName(@handle, name) check_rc(rc) self end def get_cursor_name rc, name = SQLGetCursorName(@handle) check_rc(rc) name end def row_count rc, rowcount = SQLRowCount(@handle) check_rc(rc) rowcount end def num_result_cols rc, cols = SQLNumResultCols(@handle) check_rc(rc) cols end def fetch_all if block_given? while (row=fetch) do yield row end else res = [] while (row=fetch) do res << row end res end end def fetch rc, nr_cols = SQLNumResultCols(@handle) cols = (1..nr_cols).collect do |c| rc, name, bl, type, col_sz = SQLDescribeCol(@handle, c, 1024) [name, type, col_sz] end rc = SQLFetch(@handle) if rc == SQL_NO_DATA_FOUND #SQLCloseCursor(@handle) SQLFreeStmt(@handle, SQL_CLOSE) #close cursor return nil end raise "ERROR" unless rc == SQL_SUCCESS retval = [] cols.each_with_index do |c, i| rc, content = SQLGetData(@handle, i+1, c[1], c[2] + 1) #yun added 1 to c[2] retval << content end return retval end def fetch_as_hash rc, nr_cols = SQLNumResultCols(@handle) cols = (1..nr_cols).collect do |c| rc, name, bl, type, col_sz = SQLDescribeCol(@handle, c, 1024) [name, type, col_sz] end rc = SQLFetch(@handle) if rc == SQL_NO_DATA_FOUND #SQLCloseCursor(@handle) SQLFreeStmt(@handle, SQL_CLOSE) #close cursor SQLFreeStmt(@handle, SQL_RESET_PARAMS) #reset parameters return nil end raise "ERROR" unless rc == SQL_SUCCESS retval = {} cols.each_with_index do |c, i| rc, content = SQLGetData(@handle, i+1, c[1], c[2] + 1) #yun added 1 to c[2] retval[c[0]] = content end return retval end end # class Statement class Parameter attr_reader :type, :size, :decimalDigits def initialize(type, size, decimalDigits) @type = type @size = size @decimalDigits = decimalDigits end end end # module DB2 ruby-db2-0.4/samples/test.rb0100644000175100000000000000525007535625172015462 0ustar mneumannwheel require "db2/db2cli.rb" include DB2CLI rc, env = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE); p rc puts "Datasources: " p SQLDataSources(env, SQL_FETCH_FIRST, SQL_MAX_DSN_LENGTH+1, 200) loop { a = SQLDataSources(env, SQL_FETCH_NEXT, SQL_MAX_DSN_LENGTH+1, 200) break if a[0] == SQL_NO_DATA_FOUND p a } puts "--------------------" readline rc, dbc = SQLAllocHandle(SQL_HANDLE_DBC, env); p rc p SQLConnect(dbc, "SAMPLE", "", "") rc, stmt = SQLAllocHandle(SQL_HANDLE_STMT, dbc); p rc p SQLPrepare(stmt, "SELECT * FROM EMPLOYEE") p SQLExecute(stmt) DELIM = " " rc, COLS = SQLNumResultCols(stmt) cols = (1..COLS).collect {|c| rc, name, bl, type, col_sz = SQLDescribeCol(stmt, c, 100) [name, type, col_sz] } cols.each {|c| print c[0], DELIM } puts while SQLFetch(stmt) == SQL_SUCCESS do cols.each_with_index {|c, i| rc, content = SQLGetData(stmt, i+1, c[1], 100) print content, DELIM } puts end p SQLFreeStmt(stmt, SQL_CLOSE) ################ def get_row_as_hash(stmt) rc, nr_cols = SQLNumResultCols(stmt) cols = (1..nr_cols).collect do |c| rc, name, bl, type, col_sz = SQLDescribeCol(stmt, c, 100) [name, type, col_sz] end rc = SQLFetch(stmt) return nil if rc == SQL_NO_DATA_FOUND raise "ERROR" unless rc == SQL_SUCCESS retval = {} cols.each_with_index do |c, i| rc, content = SQLGetData(stmt, i+1, c[1], c[2]) retval[c[0]] = content end return retval end ################ puts "HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH" p SQLTables(stmt, "", "", "%", "") while (c=get_row_as_hash(stmt)) p c end puts "HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH" p SQLFreeStmt(stmt, SQL_CLOSE) p SQLExecDirect(stmt, "SELECT 2, 2.3+3.4, 'Hallo' FROM EMPLOYEE") #p SQLExecDirect(stmt, "SELECT YEARS FROM STAFF WHERE YEARS IS NULL") p "*************************************" p SQLColAttribute(stmt, 2, SQL_DESC_TYPE_NAME, 200) p SQLColAttribute(stmt, 2, SQL_DESC_TYPE, nil) p "*************************************" p SQLFetch(stmt) puts "==================================" p SQLGetData(stmt, 1, SQL_INTEGER) p SQLGetData(stmt, 1, SQL_SMALLINT) p SQLGetData(stmt, 2, SQL_DOUBLE) #p SQLGetData(stmt, 2, SQL_FLOAT) #p SQLGetData(stmt, 2, SQL_REAL) p SQLGetData(stmt, 3, SQL_INTEGER, 20000) puts "==================================" p SQLFreeStmt(stmt, SQL_CLOSE) puts "-----111111111111111-----------" p SQLExecDirect(stmt, "INSERT INTO meintable (test,hallo) VALUES (2,3)") p SQLGetDiagRec(SQL_HANDLE_STMT, stmt, 1, 1000) p SQLRowCount(stmt) p SQLEndTran(SQL_HANDLE_DBC, dbc, SQL_ROLLBACK) p SQLFreeHandle(SQL_HANDLE_STMT, stmt) p SQLDisconnect(dbc) p SQLFreeHandle(SQL_HANDLE_DBC, dbc) p SQLFreeHandle(SQL_HANDLE_ENV, env) ruby-db2-0.4/samples/test2.rb0100644000175100000000000000031007535625172015534 0ustar mneumannwheelrequire "db2.rb" include DB2 env = Environment.new conn = env.createConnection("SAMPLE") stmt = conn.createStatement stmt.prepare("SELECT * FROM EMPLOYEE").execute p stmt.fetchAll conn.disconnect ruby-db2-0.4/utils/0040755000175100000000000000000007757751757013672 5ustar mneumannwheelruby-db2-0.4/utils/create_constants.rb0100644000175100000000000000263507535625172017542 0ustar mneumannwheel OTHER = %w( SQL_SUCCESS SQL_SUCCESS_WITH_INFO SQL_INVALID_HANDLE SQL_STILL_EXECUTING SQL_ERROR SQL_NO_DATA_FOUND SQL_NULL_DATA SQL_HANDLE_ENV SQL_HANDLE_DBC SQL_HANDLE_STMT SQL_HANDLE_DESC SQL_NULL_HANDLE SQL_NULL_HENV SQL_NULL_HDBC SQL_NULL_HSTMT SQL_NULL_HDESC SQL_NO_NULLS SQL_NULLABLE SQL_COMMIT SQL_ROLLBACK SQL_TRUE SQL_FALSE SQL_MAX_DSN_LENGTH SQL_BIGINT SQL_BLOB SQL_BLOB_LOCATOR SQL_CHAR SQL_BINARY SQL_CLOB SQL_CLOB_LOCATOR SQL_TYPE_DATE SQL_DBCLOB SQL_DBCLOB_LOCATOR SQL_DECIMAL SQL_DOUBLE SQL_FLOAT SQL_GRAPHIC SQL_INTEGER SQL_LONGVARCHAR SQL_LONGVARBINARY SQL_LONGVARGRAPHIC SQL_NUMERIC SQL_REAL SQL_SMALLINT SQL_TYPE_TIME SQL_TYPE_TIMESTAMP SQL_VARCHAR SQL_VARBINARY SQL_VARGRAPHIC SQL_FETCH_NEXT SQL_FETCH_PRIOR SQL_FETCH_RELATIVE SQL_FETCH_ABSOLUTE SQL_FETCH_FIRST SQL_FETCH_LAST SQL_FETCH_BOOKMARK SQL_CLOSE SQL_DROP SQL_UNBIND SQL_RESET_PARAMS ) SQL_DESC = %w( AUTO_UNIQUE_VALUE CASE_SENSITIVE CATALOG_NAME COUNT DISPLAY_SIZE LABEL DISTINCT_TYPE OCTET_LENGTH FIXED_PREC_SCALE NAME NULLABLE SCHEMA_NAME PRECISION SCALE SEARCHABLE TABLE_NAME TYPE TYPE_NAME UNSIGNED UPDATABLE BASE_COLUMN_NAME BASE_TABLE_NAME CONCISE_TYPE LENGTH LITERAL_PREFIX LITERAL_SUFFIX LOCAL_TYPE_NAME NUM_PREC_RADIX UNNAMED ).collect {|i| "SQL_DESC_#{i}"} CONSTANTS = OTHER + SQL_DESC File.open("constants.h", "w+") {|f| CONSTANTS.each {|c| f.puts %{rb_define_const(mDB2CLI, "#{c}", INT2NUM(#{c}));} } f.puts }