diff --git a/.gemtest b/.gemtest deleted file mode 100644 index e69de29..0000000 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..923a6c4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*.gem +/tmp/ +.idea/ diff --git a/ChangeLog b/ChangeLog index 72a2c5d..506a958 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,8 +1,52 @@ ODBC binding for Ruby --------------------- +Thu Jun 27 2024 version 0.103.cv release + * Argument data type fix to support Ruby 3.3 by replacing NULL with 0 in method rb_funcall + * Include ruby/thread.h to implicitly declare rb_thread_call_without_gvl + * Cast first argument of rb_thread_call_without_gvl to void * data type -HEAD - * migrated to hoe and rake-compiler for the build process +Mon Aug 21 2023 version 0.102.cv release + * Syntax changes to support Ruby 3.2 by using native "rb_str_new" instead of "rb_tainted_str_new" + Remove tained usage (thanks @vhermecz) + Fix error 'tried to create Proc object without a block (ArgumentError)' + +Tue Feb 12 2019 version 0.101.cv release + * Minor syntax changes to support Ruby 2.4 + Don't pass "" as the second parameter to has_library() + Ensure char* are passed to rb_scan_args() + +Wed August 31 2016 version 0.100.cv release + * Add support for Ruby 2.x by using native "rb_thread_call_without_gvl" directly (thanks @shreyasahir) + +Wed April 12 2014 version 0.99 release + * Remove debug log + +Wed April 8 2014 version 0.98 release + * Set login time to 30 seconds + +Wed Feb 26 2014 version 0.97 release + * Force encoding of all ruby strings in results to UTF8 if Encoding.default_external == 'UTF-8' + You must be saving and retrieving UTF8 compatible strings in the database. + +Wed Jan 16 2014 version 0.99996 released + + * Added call to rb_thread_blocking_region to release the global + interpreter lock during SQLExecute and SQLExecDirect and require it + afterwards. + + This improves performance by not blocking all Ruby threads during long + running queries. This also fixes a deadlock which can occur in SQLExecute and + SQLExecDirect which can happen when trying to read (if isolation level is + "read committed", "repeatable read", "serializable", etc.) or when trying to + modify a dirty row that has been modified by an uncommitted transaction. If this + transaction was initiated by a ruby thread in the same process, all ruby threads + will hang and the ruby process will become unresponsive. + +Wed Mar 13 2013 version 0.99995 released + + * added ODBC::Database.use_sql_column_name= flag to switch + usage of SQLColAttributes(SQL_COLUMN_LABEL) to + SQLColAttributes(SQL_COLUMN_NAME) on per connection basis Sat Jan 15 2011 version 0.99994 released @@ -74,7 +118,7 @@ Fri Sep 15 2006 version 0.9993 released * more tweaks in extconf.rb for --enable-dlopen'ed utf8 version thanks Daigo Moriwaki for testing - * eliminated warnings for installer functions + * eliminated warnings for installer functions Mon Sep 11 2006 version 0.9992 released @@ -85,7 +129,7 @@ Mon Sep 11 2006 version 0.9992 released by Neville Burnell * handle SQL_NO_DATA for chunk-wise SQLGetData() * determine dynamically which API (UNICODE or ANSI) to - use for ODBC installer functions + use for ODBC installer functions * more 64 bit fixes * added missing SQLEndTran() in init.c @@ -143,7 +187,7 @@ Tue Sep 07 2004 version 0.995 released Wed Jul 14 2004 version 0.994 released - * fixed ODBC::Database.new|connect so that + * fixed ODBC::Database.new|connect so that ODBC::Database.new.drvconnect(string) works * fixed SQLTCHAR detect for Win32 in extconf.rb, thanks to Pedro Luis Castedo Cepeda diff --git a/MANIFEST b/MANIFEST index 21b835a..b5c01e8 100644 --- a/MANIFEST +++ b/MANIFEST @@ -2,7 +2,7 @@ COPYING ChangeLog GPL MANIFEST -README +README.rd ruby-odbc.gemspec ext/extconf.rb ext/odbc.c diff --git a/Manifest.txt b/Manifest.txt deleted file mode 100644 index 0542a6c..0000000 --- a/Manifest.txt +++ /dev/null @@ -1,27 +0,0 @@ -.gemtest -COPYING -ChangeLog -GPL -MANIFEST -Manifest.txt -README.rdoc -Rakefile -doc/odbc.html -ext/extconf.rb -ext/init.c -ext/odbc.c -ext/utf8/extconf.rb -ext/utf8/init.c -ext/utf8/odbc.c -lib/cqgen.rb -lib/odbc.rb -lib/odbc_utf8.rb -test/00connect.rb -test/10create_table.rb -test/20insert.rb -test/30select.rb -test/40update.rb -test/50drop_table.rb -test/70close.rb -test/test.rb -test/utf8/test.rb diff --git a/README.rdoc b/README.rdoc index 4d5c174..d8bc8c9 100644 --- a/README.rdoc +++ b/README.rdoc @@ -2,6 +2,21 @@ * Homepage: http://www.ch-werner.de/rubyodbc/ +== CloudVolumes Improvements: + +This version releases the global interpreter lock during SQLExecute & SQLExecDirect. + +It also forces the encoding of all ruby result strings to UTF-8 if Encoding.default_external is 'UTF-8'. + +For example: + > Encoding.default_external = 'UTF-8' + > row = # some database query + > puts row[:some_string_column].encoding # UTF-8 + + +Ensure you are saving UTF-8 encoded (or compatible) strings into the database. + + == DESCRIPTION: This is an ODBC binding for Ruby. So far it has been tested with @@ -20,6 +35,12 @@ This is an ODBC binding for Ruby. So far it has been tested with - Ruby 1.8.*, SQLite/ODBC >= 0.67, libiodbc 3.52.4 on Fedora Core 3 x86 + - Ruby 2.0.0, SQLite/ODBC >= 0.93, unixODBC 2.2.14 on Ubuntu 12.04 x86 + + - Ruby 2.2.5, MSSQL/ODBC on Windows 2008R2 (AppVolumes) + + - Ruby 2.4.5, MSSQL/ODBC on Windows 2012R2 (AppVolumes) + Michael Neumann and Will Merrell reported successful compilation with Cygwin on Win32. diff --git a/doc/odbc.html b/doc/odbc.html index ec288f6..181c894 100644 --- a/doc/odbc.html +++ b/doc/odbc.html @@ -27,7 +27,7 @@

Ruby ODBC Reference

- Last update: Thu, 16 September 2010 + Last update: Wed, 13 March 2013

@@ -706,6 +706,12 @@

methods:

SQL_TIMESTAMP data types to Ruby objects. When true, Ruby Date and Time objects are represented in UTC, when false (default) in the local timezone. +
+ use_sql_column_name[=bool] +
Sets or queries the flag controlling how column names are + read from the data source. When false (default), the ODBC + API SQLColAttributes(SQL_COLUMN_LABEL) is used, + otherwise SQLColAttributes(SQL_COLUMN_NAME) is used.

singleton methods:

diff --git a/ext/extconf.rb b/ext/extconf.rb index 385ce28..77aafa1 100644 --- a/ext/extconf.rb +++ b/ext/extconf.rb @@ -1,10 +1,13 @@ require 'mkmf' -if enable_config('win32-cross-compilation') - PLATFORM = 'mingw32' -elsif ! defined? PLATFORM +if ! defined? PLATFORM PLATFORM = RUBY_PLATFORM end +# 2.0+ +#adding this for backward compatible +have_header('ruby/thread.h') && have_func('rb_thread_call_without_gvl', 'ruby/thread.h') +# 1.9-only +have_func('rb_thread_blocking_region') def have_library_ex(lib, func="main", headers=nil) checking_for "#{func}() in -l#{lib}" do @@ -19,7 +22,7 @@ def have_library_ex(lib, func="main", headers=nil) end end end - + dir_config("odbc") have_header("version.h") have_header("sql.h") || begin @@ -92,9 +95,9 @@ def have_library_ex(lib, func="main", headers=nil) have_func("SQLInstallerError", "odbcinst.h") # mingw untested !!! elsif PLATFORM =~ /(mingw|cygwin)/ then - have_library("odbc32", "") - have_library("odbccp32", "") - have_library("user32", "") + have_library("odbc32") + have_library("odbccp32") + have_library("user32") elsif (testdlopen && PLATFORM !~ /(macos|darwin)/ && CONFIG["CC"] =~ /gcc/ && have_func("dlopen", "dlfcn.h") && have_library("dl", "dlopen")) then $LDFLAGS+=" -Wl,-init -Wl,ruby_odbc_init -Wl,-fini -Wl,ruby_odbc_fini" $CPPFLAGS+=" -DHAVE_SQLCONFIGDATASOURCE" @@ -121,4 +124,4 @@ def have_library_ex(lib, func="main", headers=nil) end end -create_makefile("odbc_ext") +create_makefile("odbc") diff --git a/ext/odbc.c b/ext/odbc.c index 48594f8..45cc666 100644 --- a/ext/odbc.c +++ b/ext/odbc.c @@ -1,6 +1,6 @@ /* * ODBC-Ruby binding - * Copyright (c) 2001-2011 Christian Werner + * Copyright (c) 2001-2013 Christian Werner * Portions copyright (c) 2004 Ryszard Niewisiewicz * Portions copyright (c) 2006 Carl Blakeley * @@ -8,7 +8,7 @@ * and redistribution of this file and for a * DISCLAIMER OF ALL WARRANTIES. * - * $Id: odbc.c,v 1.72 2011/01/15 08:02:55 chw Exp chw $ + * $Id: odbc.c,v 1.75 2013/03/13 19:31:13 chw Exp chw $ */ #undef ODBCVER @@ -19,6 +19,7 @@ #include #include #include "ruby.h" +#include "ruby/thread.h" #ifdef HAVE_VERSION_H #include "version.h" #endif @@ -40,8 +41,6 @@ #include #endif -static const char *VERSION = "0.99994"; - #ifndef HAVE_TYPE_SQLTCHAR #ifdef UNICODE typedef SQLWCHAR SQLTCHAR; @@ -101,15 +100,17 @@ BOOL INSTAPI SQLReadFileDSNW(LPWSTR, LPWSTR, LPWSTR, LPWSTR, WORD, WORD *); BOOL INSTAPI SQLWriteFileDSNW(LPWSTR, LPWSTR, LPWSTR, LPWSTR); #endif +#endif /* UNICODE */ + #if defined(HAVE_RUBY_ENCODING_H) && HAVE_RUBY_ENCODING_H #define USE_RB_ENC 1 #include "ruby/encoding.h" static rb_encoding *rb_enc = NULL; +static rb_encoding *rb_external_encoding = NULL; +static int rb_encoding_is_utf8 = 0; static VALUE rb_encv = Qnil; #endif -#endif /* UNICODE */ - #ifndef HAVE_RB_DEFINE_ALLOC_FUNC #define rb_define_alloc_func(cls, func) \ rb_define_singleton_method(cls, "new", func, -1) @@ -129,7 +130,7 @@ static VALUE rb_encv = Qnil; #endif #ifdef TRACING -static int tracing = 0; +static int tracing = 1; #define tracemsg(t, x) {if (tracing & t) { x }} static SQLRETURN tracesql(SQLHENV henv, SQLHDBC hdbc, SQLHSTMT hstmt, SQLRETURN ret, const char *m); @@ -147,6 +148,73 @@ static SQLRETURN tracesql(SQLHENV henv, SQLHDBC hdbc, SQLHSTMT hstmt, #define SQL_NO_DATA SQL_NO_DATA_FOUND #endif +//////////////////////////////////////////////////////////////// + +#ifdef HAVE_RB_THREAD_BLOCKING_REGION +#define rb_thread_call_without_gvl(func, data1, ubf, data2) \ + rb_thread_blocking_region((rb_blocking_function_t *)func, data1, ubf, data2) +#endif + +typedef struct _SQLExecDirect_Args { + SQLHSTMT StatementHandle; +#ifdef _UNICODE + SQLWCHAR *StatementText; +#else + SQLCHAR *StatementText; +#endif + SQLINTEGER TextLength; +} SQLExecDirect_Args; + +typedef struct _SQLExecute_Args { + SQLHSTMT StatementHandle; +} SQLExecute_Args; + +VALUE +SQLExecute_wrapper(void *data) +{ + SQLExecute_Args *args = (SQLExecute_Args *)data; + return SQLExecute(args->StatementHandle); +} + +void * +SQLExecute_wrapper_with_gvl(void *data) { + // Call the original function + VALUE result = SQLExecute_wrapper(data); + // Cast the result to void* and return + return (void *)result; +} + +void +SQLExecute_unblock(void *data) +{ + SQLExecute_Args *args = (SQLExecute_Args *)data; + SQLCancel(args->StatementHandle); +} + +VALUE +SQLExecDirect_wrapper(void *data) +{ + SQLExecDirect_Args *args = (SQLExecDirect_Args *)data; + return SQLExecDirect(args->StatementHandle, args->StatementText, args->TextLength); +} + +void * +SQLExecDirect_wrapper_with_gvl(void *data) { + // Call the original function + VALUE result = SQLExecDirect_wrapper(data); + // Cast the result to void* and return + return (void *)result; +} + +void +SQLExecDirect_unblock(void *data) +{ + SQLExecDirect_Args *args = (SQLExecDirect_Args *)data; + SQLCancel(args->StatementHandle); +} + +//////////////////////////////////////////////////////////////// + typedef struct link { struct link *succ; struct link *pred; @@ -170,6 +238,7 @@ typedef struct dbc { VALUE rbtime; VALUE gmtime; int upc; + VALUE use_sql_column_name; } DBC; typedef struct { @@ -352,7 +421,7 @@ static const char *colnamebuf[] = { #define LEN_ALIGN(x) \ ((x) + sizeof (double) - (((x) + sizeof (double)) % sizeof (double))) - + /* *---------------------------------------------------------------------- * @@ -458,7 +527,7 @@ uc_tainted_str_new(SQLWCHAR *str, int len) if ((cp != NULL) && (str != NULL)) { ulen = mkutf(cp, str, len); } - v = rb_tainted_str_new((cp != NULL) ? cp : "", ulen); + v = rb_str_new((cp != NULL) ? cp : "", ulen); #ifdef USE_RB_ENC rb_enc_associate(v, rb_enc); #endif @@ -626,7 +695,23 @@ uc_free(SQLWCHAR *str) #endif +static VALUE +utf8_str_new(SQLCHAR *str, int len) +{ + VALUE v; + + v = rb_str_new(str, len); +#ifdef USE_RB_ENC + if(rb_encoding_is_utf8) + { + rb_enc_associate(v, rb_enc); + } +#endif + + return v; +} + /* *---------------------------------------------------------------------- * @@ -653,7 +738,7 @@ dsn_init(VALUE self) rb_iv_set(self, "@descr", Qnil); return self; } - + /* *---------------------------------------------------------------------- * @@ -680,7 +765,7 @@ drv_init(VALUE self) rb_iv_set(self, "@attrs", rb_hash_new()); return self; } - + /* *---------------------------------------------------------------------- * @@ -911,7 +996,7 @@ free_stmt(STMT *q) static void start_gc() { - rb_funcall(rb_mGC, IDstart, 0, NULL); + rb_funcall(rb_mGC, IDstart, 0, 0); } static void @@ -929,7 +1014,7 @@ mark_stmt(STMT *q) rb_gc_mark(q->dbc); } } - + /* *---------------------------------------------------------------------- * @@ -948,11 +1033,11 @@ set_err(const char *msg, int warn) rb_enc_associate(v, rb_enc); #endif a = rb_ary_new2(1); - rb_ary_push(a, rb_obj_taint(v)); + rb_ary_push(a, v); CVAR_SET(Cobj, warn ? IDatatinfo : IDataterror, a); return STR2CSTR(v); } - + /* *---------------------------------------------------------------------- * @@ -1026,7 +1111,7 @@ get_err_or_info(SQLHENV henv, SQLHDBC hdbc, SQLHSTMT hstmt, int isinfo) v0 = v; a = rb_ary_new(); } - rb_ary_push(a, rb_obj_taint(v)); + rb_ary_push(a, v); tracemsg(1, fprintf(stderr, " | %s\n", STR2CSTR(v));); } } @@ -1122,7 +1207,7 @@ get_installer_err() v0 = v; a = rb_ary_new(); } - rb_ary_push(a, rb_obj_taint(v)); + rb_ary_push(a, v); tracemsg(1, fprintf(stderr, " | %s\n", STR2CSTR(v));); } } @@ -1178,6 +1263,7 @@ tracesql(SQLHENV henv, SQLHDBC hdbc, SQLHSTMT hstmt, SQLRETURN ret, (long) henv, (long) hdbc, (long) hstmt); trace_sql_ret(ret); } + return ret; } #endif @@ -1283,7 +1369,7 @@ succeeded_nodata(SQLHENV henv, SQLHDBC hdbc, SQLHSTMT hstmt, SQLRETURN ret, } return succeeded_common(henv, hdbc, hstmt, ret, msgp); } - + /* *---------------------------------------------------------------------- * @@ -1324,7 +1410,7 @@ get_env(VALUE self) Data_Get_Struct(env_of(self), ENV, e); return e; } - + /* *---------------------------------------------------------------------- * @@ -1350,7 +1436,7 @@ get_dbc(VALUE self) Data_Get_Struct(self, DBC, p); return p; } - + /* *---------------------------------------------------------------------- * @@ -1376,12 +1462,12 @@ dbc_raise(VALUE self, VALUE msg) buf[SQL_MAX_MESSAGE_LENGTH] = '\0'; v = rb_str_new2(buf); a = rb_ary_new2(1); - rb_ary_push(a, rb_obj_taint(v)); + rb_ary_push(a, v); CVAR_SET(Cobj, IDataterror, a); rb_raise(Cerror, "%s", buf); return Qnil; } - + /* *---------------------------------------------------------------------- * @@ -1419,7 +1505,7 @@ env_new(VALUE self) #endif return obj; } - + /* *---------------------------------------------------------------------- * @@ -1466,15 +1552,15 @@ dbc_dsns(VALUE self) #else dsnLen = (dsnLen == 0) ? (SQLSMALLINT) strlen(dsn) : dsnLen; descrLen = (descrLen == 0) ? (SQLSMALLINT) strlen(descr) : descrLen; - rb_iv_set(odsn, "@name", rb_tainted_str_new(dsn, dsnLen)); - rb_iv_set(odsn, "@descr", rb_tainted_str_new(descr, descrLen)); + rb_iv_set(odsn, "@name", rb_str_new(dsn, dsnLen)); + rb_iv_set(odsn, "@descr", rb_str_new(descr, descrLen)); #endif rb_ary_push(aret, odsn); first = dsnLen = descrLen = 0; } return aret; } - + /* *---------------------------------------------------------------------- * @@ -1531,13 +1617,13 @@ dbc_drivers(VALUE self) } #else driverLen = (driverLen == 0) ? (SQLSMALLINT) strlen(driver) : driverLen; - rb_iv_set(odrv, "@name", rb_tainted_str_new(driver, driverLen)); + rb_iv_set(odrv, "@name", rb_str_new(driver, driverLen)); for (attr = attrs; *attr; attr += strlen(attr) + 1) { char *p = strchr(attr, '='); if ((p != NULL) && (p != attr)) { - rb_hash_aset(h, rb_tainted_str_new(attr, p - attr), - rb_tainted_str_new2(p + 1)); + rb_hash_aset(h, rb_str_new(attr, p - attr), + rb_str_new2(p + 1)); count++; } } @@ -1550,7 +1636,7 @@ dbc_drivers(VALUE self) } return aret; } - + /* *---------------------------------------------------------------------- * @@ -1600,7 +1686,7 @@ conf_dsn(int argc, VALUE *argv, VALUE self, int op) if (rb_obj_is_kind_of(attr, rb_cHash) == Qtrue) { VALUE a, x; - a = rb_funcall(attr, IDkeys, 0, NULL); + a = rb_funcall(attr, IDkeys, 0, 0); while ((x = rb_ary_shift(a)) != Qnil) { VALUE v = rb_hash_aref(attr, x); @@ -1846,7 +1932,7 @@ dbc_rfdsn(int argc, VALUE *argv, VALUE self) if (SQLReadFileDSN((LPCSTR) sfname, (LPCSTR) saname, (LPCSTR) skname, (LPSTR) valbuf, sizeof (valbuf), NULL)) { - return rb_tainted_str_new2((char *) valbuf); + return rb_str_new2((char *) valbuf); } } #else @@ -1856,7 +1942,7 @@ dbc_rfdsn(int argc, VALUE *argv, VALUE self) valbuf[0] = '\0'; if (SQLReadFileDSN(sfname, saname, skname, valbuf, sizeof (valbuf), NULL)) { - return rb_tainted_str_new2(valbuf); + return rb_str_new2(valbuf); } #endif #if defined(HAVE_SQLINSTALLERERROR) || (defined(UNICODE) && defined(HAVE_SQLINSTALLERERRORW)) @@ -1869,7 +1955,7 @@ dbc_rfdsn(int argc, VALUE *argv, VALUE self) return Qnil; #endif } - + /* *---------------------------------------------------------------------- * @@ -1897,7 +1983,7 @@ dbc_clrerror(VALUE self) CVAR_SET(Cobj, IDatatinfo, Qnil); return Qnil; } - + /* *---------------------------------------------------------------------- * @@ -1956,6 +2042,7 @@ dbc_new(int argc, VALUE *argv, VALUE self) list_init(&p->stmts, offsetof(STMT, link)); p->hdbc = SQL_NULL_HDBC; p->upc = 0; + p->use_sql_column_name = Qfalse; #endif if (env != Qnil) { ENV *e; @@ -1968,7 +2055,7 @@ dbc_new(int argc, VALUE *argv, VALUE self) } return obj; } - + /* *---------------------------------------------------------------------- * @@ -2061,6 +2148,20 @@ dbc_connect(int argc, VALUE *argv, VALUE self) #endif rb_raise(Cerror, "%s", msg); } + + { + SQLRETURN nRet; + + SQLUINTEGER nTimeout = 30; // Timeout + + //SQLUINTEGER nOldTimeout = 0; + //nRet = SQLGetConnectAttr(dbc, SQL_ATTR_LOGIN_TIMEOUT, (SQLPOINTER)&nOldTimeout, SQL_IS_INTEGER, NULL); + //printf("Old timeout is %d seconds, changing to %d\n", nOldTimeout, nTimeout); + + nRet = SQLSetConnectAttr(dbc, SQL_ATTR_LOGIN_TIMEOUT, (SQLPOINTER)nTimeout, SQL_IS_INTEGER); + if (!SQL_SUCCEEDED(nRet)) fprintf(stderr, "Failed to set timeout to %d: error %d\n", nTimeout, nRet); + } + if (!succeeded(SQL_NULL_HENV, dbc, SQL_NULL_HSTMT, SQLConnect(dbc, (SQLTCHAR *) sdsn, SQL_NTS, (SQLTCHAR *) suser, @@ -2104,7 +2205,7 @@ dbc_drvconnect(VALUE self, VALUE drv) VALUE d, a, x; d = rb_str_new2(""); - a = rb_funcall(rb_iv_get(drv, "@attrs"), IDkeys, 0, NULL); + a = rb_funcall(rb_iv_get(drv, "@attrs"), IDkeys, 0, 0); while ((x = rb_ary_shift(a)) != Qnil) { VALUE v = rb_hash_aref(rb_iv_get(drv, "@attrs"), x); @@ -2197,6 +2298,20 @@ dbc_timeutc(int argc, VALUE *argv, VALUE self) return p->gmtime; } +static VALUE +dbc_use_scn(int argc, VALUE *argv, VALUE self) +{ + DBC *p = get_dbc(self); + VALUE val; + + if (argc > 0) { + rb_scan_args(argc, argv, "1", &val); + p->use_sql_column_name = + (val != Qnil && val != Qfalse) ? Qtrue : Qfalse; + } + return p->use_sql_column_name; +} + /* *---------------------------------------------------------------------- * @@ -2220,7 +2335,7 @@ dbc_dropall(VALUE self) } return self; } - + /* *---------------------------------------------------------------------- * @@ -2257,7 +2372,7 @@ dbc_disconnect(int argc, VALUE *argv, VALUE self) } return Qfalse; } - + /* *---------------------------------------------------------------------- * @@ -3171,7 +3286,7 @@ dbc_getinfo(int argc, VALUE *argv, VALUE self) } return Qnil; } - + /* *---------------------------------------------------------------------- * @@ -3185,7 +3300,7 @@ make_coltypes(SQLHSTMT hstmt, int ncols, char **msgp) { int i; COLTYPE *ret = NULL; - SQLLEN type, size; + SQLLEN type, size = 0; for (i = 0; i < ncols; i++) { SQLUSMALLINT ic = i + 1; @@ -3322,7 +3437,7 @@ make_coltypes(SQLHSTMT hstmt, int ncols, char **msgp) } return ret; } - + /* *---------------------------------------------------------------------- * @@ -3402,7 +3517,7 @@ retain_paraminfo_override(STMT *q, int nump, PARAMINFO *paraminfo) } } } - + /* *---------------------------------------------------------------------- * @@ -3447,7 +3562,7 @@ wrap_stmt(VALUE dbc, DBC *p, SQLHSTMT hstmt, STMT **qp) } return stmt; } - + /* *---------------------------------------------------------------------- * @@ -3557,7 +3672,7 @@ upcase_if(char *string, int upc) } return string; } - + /* *---------------------------------------------------------------------- * @@ -3567,7 +3682,7 @@ upcase_if(char *string, int upc) */ static VALUE -make_column(SQLHSTMT hstmt, int i, int upc) +make_column(SQLHSTMT hstmt, int i, int upc, int use_scn) { VALUE obj, v; SQLUSMALLINT ic = i + 1; @@ -3582,10 +3697,12 @@ make_column(SQLHSTMT hstmt, int i, int upc) name[0] = 0; if (!succeeded(SQL_NULL_HENV, SQL_NULL_HDBC, hstmt, - SQLColAttributes(hstmt, ic, SQL_COLUMN_LABEL, name, + SQLColAttributes(hstmt, ic, use_scn ? SQL_COLUMN_NAME : + SQL_COLUMN_LABEL, name, (SQLSMALLINT) sizeof (name), &name_len, NULL), - &msg, "SQLColAttributes(SQL_COLUMN_LABEL)")) { + &msg, use_scn ? "SQLColAttributes(SQL_COLUMN_NAME)" : + "SQLColAttributes(SQL_COLUMN_LABEL)")) { rb_raise(Cerror, "%s", msg); } obj = rb_obj_alloc(Ccolumn); @@ -3607,7 +3724,7 @@ make_column(SQLHSTMT hstmt, int i, int upc) len = 0; } mkutf(tmp, name, len); - v = rb_tainted_str_new2(upcase_if(tmp, 1)); + v = rb_str_new2(upcase_if(tmp, 1)); #ifdef USE_RB_ENC rb_enc_associate(v, rb_enc); #endif @@ -3619,7 +3736,7 @@ make_column(SQLHSTMT hstmt, int i, int upc) rb_iv_set(obj, "@name", uc_tainted_str_new2(name)); } #else - rb_iv_set(obj, "@name", rb_tainted_str_new2(upcase_if(name, upc))); + rb_iv_set(obj, "@name", rb_str_new2(upcase_if(name, upc))); #endif v = Qnil; name[0] = 0; @@ -3637,7 +3754,7 @@ make_column(SQLHSTMT hstmt, int i, int upc) #ifdef UNICODE v = uc_tainted_str_new2(name); #else - v = rb_tainted_str_new2(name); + v = rb_str_new2(name); #endif } rb_iv_set(obj, "@table", v); @@ -3727,7 +3844,7 @@ make_column(SQLHSTMT hstmt, int i, int upc) rb_iv_set(obj, "@autoincrement", v); return obj; } - + /* *---------------------------------------------------------------------- * @@ -3767,7 +3884,7 @@ make_param(STMT *q, int i) rb_iv_set(obj, "@output_type", INT2NUM(v)); return obj; } - + /* *---------------------------------------------------------------------- * @@ -4051,7 +4168,7 @@ dbc_speccols(int argc, VALUE *argv, VALUE self) { return dbc_info(argc, argv, self, INFO_SPECCOLS); } - + /* *---------------------------------------------------------------------- * @@ -4146,7 +4263,7 @@ dbc_transaction(VALUE self) rb_funcall(ret, IDto_s, 0, 0))); return Qnil; } - + /* *---------------------------------------------------------------------- * @@ -4227,7 +4344,7 @@ env_odbcver(int argc, VALUE *argv, VALUE self) rb_raise(Cerror, "%s", set_err("Unsupported in ODBC < 3.0", 0)); #endif } - + /* *---------------------------------------------------------------------- * @@ -4281,8 +4398,11 @@ do_option(int argc, VALUE *argv, VALUE self, int isstmt, int op) SQLINTEGER v; char *msg; int level = isstmt ? OPT_LEVEL_STMT : OPT_LEVEL_DBC; - - rb_scan_args(argc, argv, (op == -1) ? "11" : "01", &val, &val2); + char *opvalue = "01"; + if(op == -1) { + opvalue == "11"; + } + rb_scan_args(argc, argv, opvalue, &val, &val2); if (isstmt) { Data_Get_Struct(self, STMT, q); if (q->dbc == Qnil) { @@ -4519,7 +4639,7 @@ stmt_getsetoption(int argc, VALUE *argv, VALUE self) { return do_option(argc, argv, self, 1, -1); } - + /* *---------------------------------------------------------------------- * @@ -4597,7 +4717,7 @@ scan_dtts(VALUE str, int do_d, int do_t, TIMESTAMP_STRUCT *ts) } return 0; } - + /* *---------------------------------------------------------------------- * @@ -4695,16 +4815,16 @@ date_init(int argc, VALUE *argv, VALUE self) if (argc > 1) { rb_raise(rb_eArgError, "wrong # arguments"); } - d = rb_funcall(y, IDday, 0, NULL); - m = rb_funcall(y, IDmonth, 0, NULL); - y = rb_funcall(y, IDyear, 0, NULL); + d = rb_funcall(y, IDday, 0, 0); + m = rb_funcall(y, IDmonth, 0, 0); + y = rb_funcall(y, IDyear, 0, 0); } else if (rb_obj_is_kind_of(y, rb_cDate) == Qtrue) { if (argc > 1) { rb_raise(rb_eArgError, "wrong # arguments"); } - d = rb_funcall(y, IDmday, 0, NULL); - m = rb_funcall(y, IDmonth, 0, NULL); - y = rb_funcall(y, IDyear, 0, NULL); + d = rb_funcall(y, IDmday, 0, 0); + m = rb_funcall(y, IDmonth, 0, 0); + y = rb_funcall(y, IDyear, 0, 0); } else if ((argc == 1) && (rb_obj_is_kind_of(y, rb_cString) == Qtrue)) { if (date_load1(self, y, 0) != Qnil) { return self; @@ -4832,7 +4952,7 @@ date_cmp(VALUE self, VALUE date) } return INT2FIX(1); } - + /* *---------------------------------------------------------------------- * @@ -4930,9 +5050,9 @@ time_init(int argc, VALUE *argv, VALUE self) if (argc > 1) { rb_raise(rb_eArgError, "wrong # arguments"); } - s = rb_funcall(h, IDsec, 0, NULL); - m = rb_funcall(h, IDmin, 0, NULL); - h = rb_funcall(h, IDhour, 0, NULL); + s = rb_funcall(h, IDsec, 0, 0); + m = rb_funcall(h, IDmin, 0, 0); + h = rb_funcall(h, IDhour, 0, 0); } else if ((argc == 1) && (rb_obj_is_kind_of(h, rb_cString) == Qtrue)) { if (time_load1(self, h, 0) != Qnil) { return self; @@ -5060,7 +5180,7 @@ time_cmp(VALUE self, VALUE time) } return INT2FIX(1); } - + /* *---------------------------------------------------------------------- * @@ -5170,13 +5290,13 @@ timestamp_init(int argc, VALUE *argv, VALUE self) if (argc > 1) { rb_raise(rb_eArgError, "wrong # arguments"); } - f = rb_funcall(y, IDusec, 0, NULL); - ss = rb_funcall(y, IDsec, 0, NULL); - mm = rb_funcall(y, IDmin, 0, NULL); - hh = rb_funcall(y, IDhour, 0, NULL); - d = rb_funcall(y, IDday, 0, NULL); - m = rb_funcall(y, IDmonth, 0, NULL); - y = rb_funcall(y, IDyear, 0, NULL); + f = rb_funcall(y, IDusec, 0, 0); + ss = rb_funcall(y, IDsec, 0, 0); + mm = rb_funcall(y, IDmin, 0, 0); + hh = rb_funcall(y, IDhour, 0, 0); + d = rb_funcall(y, IDday, 0, 0); + m = rb_funcall(y, IDmonth, 0, 0); + y = rb_funcall(y, IDyear, 0, 0); f = INT2NUM(NUM2INT(f) * 1000); } else if (rb_obj_is_kind_of(y, rb_cDate) == Qtrue) { if (argc > 1) { @@ -5186,9 +5306,9 @@ timestamp_init(int argc, VALUE *argv, VALUE self) ss = INT2FIX(0); mm = INT2FIX(0); hh = INT2FIX(0); - d = rb_funcall(y, IDmday, 0, NULL); - m = rb_funcall(y, IDmonth, 0, NULL); - y = rb_funcall(y, IDyear, 0, NULL); + d = rb_funcall(y, IDmday, 0, 0); + m = rb_funcall(y, IDmonth, 0, 0); + y = rb_funcall(y, IDyear, 0, 0); } else if ((argc == 1) && (rb_obj_is_kind_of(y, rb_cString) == Qtrue)) { if (timestamp_load1(self, y, 0) != Qnil) { return self; @@ -5403,7 +5523,7 @@ timestamp_cmp(VALUE self, VALUE timestamp) } return INT2FIX(1); } - + /* *---------------------------------------------------------------------- * @@ -5663,13 +5783,13 @@ stmt_param_output_value(int argc, VALUE *argv, VALUE self) time = (TIME_STRUCT *) q->paraminfo[vnum].outbuf; frac = rb_float_new(0.0); - now = rb_funcall(rb_cTime, IDnow, 0, NULL); + now = rb_funcall(rb_cTime, IDnow, 0, 0); v = rb_funcall(rb_cTime, (q->dbcp->gmtime == Qtrue) ? IDutc : IDlocal, 7, - rb_funcall(now, IDyear, 0, NULL), - rb_funcall(now, IDmonth, 0, NULL), - rb_funcall(now, IDday, 0, NULL), + rb_funcall(now, IDyear, 0, 0), + rb_funcall(now, IDmonth, 0, 0), + rb_funcall(now, IDday, 0, 0), INT2NUM(time->hour), INT2NUM(time->minute), INT2NUM(time->second), @@ -5713,7 +5833,7 @@ stmt_param_output_value(int argc, VALUE *argv, VALUE self) break; #endif case SQL_C_CHAR: - v = rb_tainted_str_new(q->paraminfo[vnum].outbuf, + v = utf8_str_new(q->paraminfo[vnum].outbuf, q->paraminfo[vnum].rlen); break; } @@ -5789,7 +5909,7 @@ stmt_cursorname(int argc, VALUE *argv, VALUE self) return uc_tainted_str_new(cname, cnLen); #else cnLen = (cnLen == 0) ? (SQLSMALLINT) strlen((char *) cname) : cnLen; - return rb_tainted_str_new((char *) cname, cnLen); + return rb_str_new((char *) cname, cnLen); #endif } if (TYPE(cn) != T_STRING) { @@ -5825,27 +5945,34 @@ stmt_column(int argc, VALUE *argv, VALUE self) { STMT *q; VALUE col; + int use_scn = 0; rb_scan_args(argc, argv, "1", &col); Check_Type(col, T_FIXNUM); Data_Get_Struct(self, STMT, q); check_ncols(q); - return make_column(q->hstmt, FIX2INT(col), q->upc); + if (q->dbcp != NULL && q->dbcp->use_sql_column_name == Qtrue) { + use_scn = 1; + } + return make_column(q->hstmt, FIX2INT(col), q->upc, use_scn); } static VALUE stmt_columns(int argc, VALUE *argv, VALUE self) { STMT *q; - int i; + int i, use_scn = 0; VALUE res, as_ary = Qfalse; rb_scan_args(argc, argv, "01", &as_ary); Data_Get_Struct(self, STMT, q); check_ncols(q); + if (q->dbcp != NULL && q->dbcp->use_sql_column_name == Qtrue) { + use_scn = 1; + } if (rb_block_given_p()) { for (i = 0; i < q->ncols; i++) { - rb_yield(make_column(q->hstmt, i, q->upc)); + rb_yield(make_column(q->hstmt, i, q->upc, use_scn)); } return self; } @@ -5857,7 +5984,7 @@ stmt_columns(int argc, VALUE *argv, VALUE self) for (i = 0; i < q->ncols; i++) { VALUE obj; - obj = make_column(q->hstmt, i, q->upc); + obj = make_column(q->hstmt, i, q->upc, use_scn); if (RTEST(as_ary)) { rb_ary_store(res, i, obj); } else { @@ -5868,7 +5995,7 @@ stmt_columns(int argc, VALUE *argv, VALUE self) sprintf(buf, "#%d", i); name = rb_str_dup(name); - name = rb_obj_taint(rb_str_cat2(name, buf)); + name = rb_str_cat2(name, buf); } rb_hash_aset(res, name, obj); } @@ -5920,7 +6047,7 @@ stmt_params(VALUE self) static VALUE do_fetch(STMT *q, int mode) { - int i, offc; + int i, use_scn = 0, offc; char **bufs, *msg; VALUE res; @@ -5960,6 +6087,9 @@ do_fetch(STMT *q, int mode) } } } + if (q->dbcp != NULL && q->dbcp->use_sql_column_name == Qtrue) { + use_scn = 1; + } switch (mode & DOFETCH_MODES) { case DOFETCH_HASH: case DOFETCH_HASH2: @@ -6010,10 +6140,13 @@ do_fetch(STMT *q, int mode) if (!succeeded(SQL_NULL_HENV, SQL_NULL_HDBC, q->hstmt, SQLColAttributes(q->hstmt, (SQLUSMALLINT) (i + 1), + use_scn ? SQL_COLUMN_NAME : SQL_COLUMN_LABEL, name, sizeof (name), &name_len, NULL), - &msg, "SQLColAttributes(SQL_COLUMN_LABEL)")) { + &msg, use_scn ? + "SQLColAttributes(SQL_COLUMN_NAME)" : + "SQLColAttributes(SQL_COLUMN_LABEL)")) { rb_raise(Cerror, "%s", msg); } if (name_len >= (SQLSMALLINT) sizeof (name)) { @@ -6066,8 +6199,10 @@ do_fetch(STMT *q, int mode) name[0] = 0; callsql(SQL_NULL_HENV, SQL_NULL_HDBC, q->hstmt, SQLColAttributes(q->hstmt, (SQLUSMALLINT) (i + 1), + use_scn ? SQL_COLUMN_NAME : SQL_COLUMN_LABEL, name, sizeof (name), &name_len, NULL), + use_scn ? "SQLColAttributes(SQL_COLUMN_NAME)" : "SQLColAttributes(SQL_COLUMN_LABEL)"); if (name_len >= (SQLSMALLINT) sizeof (name)) { name_len = sizeof (name) - 1; @@ -6109,7 +6244,7 @@ do_fetch(STMT *q, int mode) } for (i = 0; i < 4 * q->ncols; i++) { res = colbuf[i / q->ncols]; - cname = rb_tainted_str_new2(q->colnames[i]); + cname = rb_str_new2(q->colnames[i]); #ifdef USE_RB_ENC rb_enc_associate(cname, rb_enc); #endif @@ -6117,7 +6252,7 @@ do_fetch(STMT *q, int mode) if (rb_funcall(res, IDkeyp, 1, cname) == Qtrue) { char *p; - cname = rb_tainted_str_new2(q->colnames[i]); + cname = rb_str_new2(q->colnames[i]); #ifdef USE_RB_ENC rb_enc_associate(cname, rb_enc); #endif @@ -6305,14 +6440,14 @@ do_fetch(STMT *q, int mode) time = (TIME_STRUCT *) valp; frac = rb_float_new(0.0); - now = rb_funcall(rb_cTime, IDnow, 0, NULL); + now = rb_funcall(rb_cTime, IDnow, 0, 0); v = rb_funcall(rb_cTime, (q->dbcp->gmtime == Qtrue) ? IDutc : IDlocal, 7, - rb_funcall(now, IDyear, 0, NULL), - rb_funcall(now, IDmonth, 0, NULL), - rb_funcall(now, IDday, 0, NULL), + rb_funcall(now, IDyear, 0, 0), + rb_funcall(now, IDmonth, 0, 0), + rb_funcall(now, IDday, 0, 0), INT2NUM(time->hour), INT2NUM(time->minute), INT2NUM(time->second), @@ -6358,7 +6493,7 @@ do_fetch(STMT *q, int mode) break; #endif default: - v = rb_tainted_str_new(valp, curlen); + v = utf8_str_new(valp, curlen); break; } } @@ -6371,14 +6506,14 @@ do_fetch(STMT *q, int mode) valp = q->colnames[i + offc]; name = (q->colvals == NULL) ? Qnil : q->colvals[i + offc]; if (name == Qnil) { - name = rb_tainted_str_new2(valp); + name = rb_str_new2(valp); #ifdef USE_RB_ENC rb_enc_associate(name, rb_enc); #endif if (rb_funcall(res, IDkeyp, 1, name) == Qtrue) { char *p; - name = rb_tainted_str_new2(valp); + name = rb_str_new2(valp); #ifdef USE_RB_ENC rb_enc_associate(name, rb_enc); #endif @@ -6974,10 +7109,14 @@ stmt_prep_int(int argc, VALUE *argv, VALUE self, int mode) #endif if ((mode & MAKERES_EXECD)) { SQLRETURN ret; + SQLExecDirect_Args args; - if (!succeeded_nodata(SQL_NULL_HENV, SQL_NULL_HDBC, hstmt, - (ret = SQLExecDirect(hstmt, ssql, SQL_NTS)), - &msg, "SQLExecDirect('%s')", csql)) { + args.StatementHandle = hstmt; + args.StatementText = ssql; + args.TextLength = SQL_NTS; + ret = (SQLRETURN)rb_thread_call_without_gvl(SQLExecDirect_wrapper_with_gvl, &args, SQLExecDirect_unblock, &args); + + if (!succeeded_nodata(SQL_NULL_HENV, SQL_NULL_HDBC, hstmt, ret, &msg, "SQLExecDirect('%s')", csql)) { goto sqlerr; } if (ret == SQL_NO_DATA) { @@ -7167,9 +7306,9 @@ bind_one_param(int pnum, VALUE arg, STMT *q, char **msgp, int *outpp) ctype = SQL_C_TIME; time = (TIME_STRUCT *) valp; memset(time, 0, sizeof (TIME_STRUCT)); - time->hour = rb_funcall(arg, IDhour, 0, NULL); - time->minute = rb_funcall(arg, IDmin, 0, NULL); - time->second = rb_funcall(arg, IDsec, 0, NULL); + time->hour = rb_funcall(arg, IDhour, 0, 0); + time->minute = rb_funcall(arg, IDmin, 0, 0); + time->second = rb_funcall(arg, IDsec, 0, 0); rlen = 1; vlen = sizeof (TIME_STRUCT); } else if (q->paraminfo[pnum].type == SQL_DATE) { @@ -7178,9 +7317,9 @@ bind_one_param(int pnum, VALUE arg, STMT *q, char **msgp, int *outpp) ctype = SQL_C_DATE; date = (DATE_STRUCT *) valp; memset(date, 0, sizeof (DATE_STRUCT)); - date->year = rb_funcall(arg, IDyear, 0, NULL); - date->month = rb_funcall(arg, IDmonth, 0, NULL); - date->day = rb_funcall(arg, IDday, 0, NULL); + date->year = rb_funcall(arg, IDyear, 0, 0); + date->month = rb_funcall(arg, IDmonth, 0, 0); + date->day = rb_funcall(arg, IDday, 0, 0); rlen = 1; vlen = sizeof (TIMESTAMP_STRUCT); } else { @@ -7189,16 +7328,16 @@ bind_one_param(int pnum, VALUE arg, STMT *q, char **msgp, int *outpp) ctype = SQL_C_TIMESTAMP; ts = (TIMESTAMP_STRUCT *) valp; memset(ts, 0, sizeof (TIMESTAMP_STRUCT)); - ts->year = rb_funcall(arg, IDyear, 0, NULL); - ts->month = rb_funcall(arg, IDmonth, 0, NULL); - ts->day = rb_funcall(arg, IDday, 0, NULL); - ts->hour = rb_funcall(arg, IDhour, 0, NULL); - ts->minute = rb_funcall(arg, IDmin, 0, NULL); - ts->second = rb_funcall(arg, IDsec, 0, NULL); + ts->year = rb_funcall(arg, IDyear, 0, 0); + ts->month = rb_funcall(arg, IDmonth, 0, 0); + ts->day = rb_funcall(arg, IDday, 0, 0); + ts->hour = rb_funcall(arg, IDhour, 0, 0); + ts->minute = rb_funcall(arg, IDmin, 0, 0); + ts->second = rb_funcall(arg, IDsec, 0, 0); #ifdef TIME_USE_USEC - ts->fraction = rb_funcall(arg, IDusec, 0, NULL) * 1000; + ts->fraction = rb_funcall(arg, IDusec, 0, 0) * 1000; #else - ts->fraction = rb_funcall(arg, IDnsec, 0, NULL); + ts->fraction = rb_funcall(arg, IDnsec, 0, 0); #endif rlen = 1; vlen = sizeof (TIMESTAMP_STRUCT); @@ -7211,9 +7350,9 @@ bind_one_param(int pnum, VALUE arg, STMT *q, char **msgp, int *outpp) ctype = SQL_C_DATE; date = (DATE_STRUCT *) valp; memset(date, 0, sizeof (DATE_STRUCT)); - date->year = rb_funcall(arg, IDyear, 0, NULL); - date->month = rb_funcall(arg, IDmonth, 0, NULL); - date->day = rb_funcall(arg, IDmday, 0, NULL); + date->year = rb_funcall(arg, IDyear, 0, 0); + date->month = rb_funcall(arg, IDmonth, 0, 0); + date->day = rb_funcall(arg, IDmday, 0, 0); rlen = 1; vlen = sizeof (DATE_STRUCT); break; @@ -7391,6 +7530,7 @@ stmt_exec_int(int argc, VALUE *argv, VALUE self, int mode) int i, argnum, has_out_parms = 0; char *msg = NULL; SQLRETURN ret; + SQLExecute_Args args; Data_Get_Struct(self, STMT, q); if (argc > q->nump - ((EXEC_PARMXOUT(mode) < 0) ? 0 : 1)) { @@ -7421,9 +7561,11 @@ stmt_exec_int(int argc, VALUE *argv, VALUE self, int mode) goto error; } } - if (!succeeded_nodata(SQL_NULL_HENV, SQL_NULL_HDBC, q->hstmt, - (ret = SQLExecute(q->hstmt)), - &msg, "SQLExecute")) { + + args.StatementHandle = q->hstmt; + ret = (SQLRETURN)rb_thread_call_without_gvl(SQLExecute_wrapper_with_gvl, &args, SQLExecute_unblock, &args); + + if (!succeeded_nodata(SQL_NULL_HENV, SQL_NULL_HDBC, q->hstmt, ret, &msg, "SQLExecute")) { error: #ifdef UNICODE for (i = 0; i < q->nump; i++) { @@ -7522,7 +7664,7 @@ stmt_ignorecase(int argc, VALUE *argv, VALUE self) } return *flag ? Qtrue : Qfalse; } - + /* *---------------------------------------------------------------------- * @@ -7545,7 +7687,7 @@ stmt_new(VALUE self) } return wrap_stmt(self, p, hstmt, NULL); } - + /* *---------------------------------------------------------------------- * @@ -7589,8 +7731,9 @@ stmt_proc_call(int argc, VALUE *argv, VALUE self) static VALUE stmt_proc(int argc, VALUE *argv, VALUE self) { - VALUE sql, ptype, psize, pnum = Qnil, stmt, args[2]; + VALUE sql, ptype, psize, pnum = Qnil, stmt, args[2], proc_args[2], proc_arg[1]; int parnum = 0; + VALUE block = rb_block_proc(); rb_scan_args(argc, argv, "13", &sql, &ptype, &psize, &pnum); if (!rb_block_given_p()) { @@ -7598,7 +7741,8 @@ stmt_proc(int argc, VALUE *argv, VALUE self) } stmt = stmt_prep_int(1, &sql, self, 0); if (argc == 1) { - return rb_funcall(Cproc, IDnew, 1, stmt); + proc_arg[0] = stmt; + return rb_funcall_with_block(Cproc, IDnew, 1, proc_arg, block); } if ((argc < 4) || (pnum == Qnil)) { pnum = INT2NUM(parnum); @@ -7616,13 +7760,18 @@ stmt_proc(int argc, VALUE *argv, VALUE self) args[1] = INT2NUM(256); } stmt_param_output_size(2, args, stmt); - return rb_funcall(Cproc, IDnew, 2, stmt, pnum); + + proc_args[0] = stmt; + proc_args[1] = pnum; + + return rb_funcall_with_block(Cproc, IDnew, 2, proc_args, block); } static VALUE stmt_procwrap(int argc, VALUE *argv, VALUE self) { - VALUE arg0 = Qnil, arg1 = Qnil; + VALUE arg0 = Qnil, arg1 = Qnil, proc_args[2]; + VALUE block = rb_block_proc(); rb_scan_args(argc, argv, "02", &arg0, &arg1); if (rb_obj_is_kind_of(self, Cstmt) == Qtrue) { @@ -7634,9 +7783,12 @@ stmt_procwrap(int argc, VALUE *argv, VALUE self) } else if (rb_obj_is_kind_of(arg0, Cstmt) != Qtrue) { rb_raise(rb_eTypeError, "need ODBC::Statement as 1st argument"); } - return rb_funcall(Cproc, IDnew, 2, arg0, arg1); -} + proc_args[0] = arg0; + proc_args[1] = arg1; + return rb_funcall_with_block(Cproc, IDnew, 2, proc_args, block); +} + /* *---------------------------------------------------------------------- * @@ -7727,7 +7879,7 @@ mod_2time(int argc, VALUE *argv, VALUE self) rb_raise(rb_eTypeError, "expecting ODBC::Date"); } } else { - VALUE now = rb_funcall(rb_cTime, IDnow, 0, NULL); + VALUE now = rb_funcall(rb_cTime, IDnow, 0, 0); y = rb_funcall(rb_cTime, IDyear, 1, now); m = rb_funcall(rb_cTime, IDmonth, 1, now); @@ -7819,7 +7971,7 @@ mod_trace(int argc, VALUE *argv, VALUE self) return INT2NUM(0); #endif } - + /* *---------------------------------------------------------------------- * @@ -8072,7 +8224,7 @@ static struct { { &IDlocal, "local" }, { &IDto_s, "to_s" } }; - + /* *---------------------------------------------------------------------- * @@ -8083,9 +8235,9 @@ static struct { void #ifdef UNICODE -Init_odbc_utf8_ext() +Init_odbc_utf8() #else -Init_odbc_ext() +Init_odbc() #endif { int i; @@ -8115,10 +8267,6 @@ Init_odbc_ext() } Modbc = rb_define_module(modname); - - /* Library version */ - rb_define_const(Modbc, "VERSION", rb_str_new2(VERSION) ); - Cobj = rb_define_class_under(Modbc, "Object", rb_cObject); rb_define_class_variable(Cobj, "@@error", Qnil); rb_define_class_variable(Cobj, "@@info", Qnil); @@ -8253,6 +8401,8 @@ Init_odbc_ext() rb_define_method(Cdbc, "use_time=", dbc_timefmt, -1); rb_define_method(Cdbc, "use_utc", dbc_timeutc, -1); rb_define_method(Cdbc, "use_utc=", dbc_timeutc, -1); + rb_define_method(Cdbc, "use_sql_column_name", dbc_use_scn, -1); + rb_define_method(Cdbc, "use_sql_column_name=", dbc_use_scn, -1); /* connection options */ rb_define_method(Cdbc, "get_option", dbc_getsetoption, -1); @@ -8433,6 +8583,16 @@ Init_odbc_ext() #endif #else rb_define_const(Modbc, "UTF8", Qfalse); +#ifdef USE_RB_ENC + rb_enc = rb_utf8_encoding(); + rb_external_encoding = rb_default_external_encoding(); + + if( rb_enc && rb_external_encoding && rb_enc == rb_external_encoding ) + { + printf("Ruby-ODBC: Force Encoding ruby result strings to UTF-8\n"); + rb_encoding_is_utf8 = 1; + } +#endif #endif #ifdef TRACING diff --git a/ext/utf8/extconf.rb b/ext/utf8/extconf.rb index d681767..aa99196 100644 --- a/ext/utf8/extconf.rb +++ b/ext/utf8/extconf.rb @@ -1,8 +1,6 @@ require 'mkmf' -if enable_config('win32-cross-compilation') - PLATFORM = 'mingw32' -elsif ! defined? PLATFORM +if ! defined? PLATFORM PLATFORM = RUBY_PLATFORM end @@ -40,7 +38,7 @@ def have_func_nolink(func, headers = nil, &b) end end end - + dir_config("odbc") have_header("sql.h") || begin puts "ERROR: sql.h not found" @@ -114,16 +112,16 @@ def have_func_nolink(func, headers = nil, &b) have_func("SQLReadFileDSNW", "odbcinst.h") have_func("SQLInstallerError", "odbcinst.h") have_func("SQLInstallerErrorW", "odbcinst.h") -# mingw untested !!! elsif PLATFORM =~ /(mingw|cygwin)/ then - have_library("odbc32", "") - have_library("odbccp32", "") - have_library("user32", "") - have_func("SQLConfigDataSourceW", "odbcinst.h") - have_func("SQLWriteFileDSNW", "odbcinst.h") - have_func("SQLReadFileDSNW", "odbcinst.h") - have_func("SQLInstallerError", "odbcinst.h") - have_func("SQLInstallerErrorW", "odbcinst.h") + have_library("odbc32") + have_library("odbccp32") + have_library("user32") + header = ["windows.h", "odbcinst.h"] + have_func("SQLConfigDataSourceW", header) + have_func("SQLWriteFileDSNW", header) + have_func("SQLReadFileDSNW", header) + have_func("SQLInstallerError", header) + have_func("SQLInstallerErrorW", header) elsif (testdlopen && PLATFORM !~ /(macos|darwin)/ && CONFIG["CC"] =~ /gcc/ && have_func("dlopen", "dlfcn.h") && have_library("dl", "dlopen")) then $LDFLAGS+=" -Wl,-init -Wl,ruby_odbc_init -Wl,-fini -Wl,ruby_odbc_fini" $CPPFLAGS+=" -DHAVE_SQLCONFIGDATASOURCE" @@ -155,4 +153,4 @@ def have_func_nolink(func, headers = nil, &b) have_func("SQLInstallerErrorW", "odbcinst.h") end -create_makefile("odbc_utf8_ext") +create_makefile("odbc_utf8") diff --git a/lib/odbc.rb b/lib/odbc.rb deleted file mode 100644 index 90565ec..0000000 --- a/lib/odbc.rb +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/env ruby - -# Extend the search path for Windows binary gem, depending of the current ruby version -major_minor = RUBY_VERSION[ /^(\d+\.\d+)/ ] or - raise "Oops, can't extract the major/minor version from #{RUBY_VERSION.dump}" -$: << File.join(File.dirname(__FILE__), major_minor) - -require 'odbc_ext' diff --git a/lib/odbc_utf8.rb b/lib/odbc_utf8.rb deleted file mode 100644 index 8057d60..0000000 --- a/lib/odbc_utf8.rb +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/env ruby - -# Extend the search path for Windows binary gem, depending of the current ruby version -major_minor = RUBY_VERSION[ /^(\d+\.\d+)/ ] or - raise "Oops, can't extract the major/minor version from #{RUBY_VERSION.dump}" -$: << File.join(File.dirname(__FILE__), major_minor) - -require 'odbc_utf8_ext' diff --git a/ruby-odbc.gemspec b/ruby-odbc.gemspec new file mode 100644 index 0000000..407a982 --- /dev/null +++ b/ruby-odbc.gemspec @@ -0,0 +1,16 @@ +require 'date' +spec = Gem::Specification.new do |s| + s.name = "ruby-odbc" + s.version = "0.103.cv" + s.date = Date.today.to_s + s.author = "Christian Werner" + s.email = "chw @nospam@ ch-werner.de" + s.summary = "ODBC binding for Ruby" + s.homepage = "http://www.ch-werner.de/rubyodbc" + s.files = Dir.glob("**/*") + s.require_paths << 'lib' + s.test_files = Dir.glob('tests/*.rb') + s.has_rdoc = false + s.extra_rdoc_files = ["README.rdoc", "COPYING", "ChangeLog", "GPL", "doc/odbc.html"] + s.extensions = ["ext/extconf.rb", "ext/utf8/extconf.rb"] +end