From nobody at rubyforge.org Sun Feb 17 05:31:04 2008 From: nobody at rubyforge.org (nobody at rubyforge.org) Date: Sun, 17 Feb 2008 05:31:04 -0500 (EST) Subject: [ruby-oci8-commit] [243] branches/ruby-oci8-1.0: * test/config.rb, test/test_break.rb, test/ test_dbi.rb, Message-ID: <20080217103104.E9C991858600@rubyforge.org> Revision: 243 Author: kubo Date: 2008-02-17 05:31:02 -0500 (Sun, 17 Feb 2008) Log Message: ----------- * test/config.rb, test/test_break.rb, test/test_dbi.rb, test/test_dbi_clob.rb, test/test_metadata.rb, test/test_oci8.rb sleep a few seconds and retry if an attempt to connect to a database server fails and its error code is ORA-12516 or ORA-12520 in test cases. Modified Paths: -------------- branches/ruby-oci8-1.0/ChangeLog branches/ruby-oci8-1.0/test/config.rb branches/ruby-oci8-1.0/test/test_break.rb branches/ruby-oci8-1.0/test/test_dbi.rb branches/ruby-oci8-1.0/test/test_dbi_clob.rb branches/ruby-oci8-1.0/test/test_metadata.rb branches/ruby-oci8-1.0/test/test_oci8.rb Modified: branches/ruby-oci8-1.0/ChangeLog =================================================================== --- branches/ruby-oci8-1.0/ChangeLog 2008-01-15 15:52:14 UTC (rev 242) +++ branches/ruby-oci8-1.0/ChangeLog 2008-02-17 10:31:02 UTC (rev 243) @@ -1,3 +1,10 @@ +2008-02-17 KUBO Takehiro + * test/config.rb, test/test_break.rb, test/test_dbi.rb, + test/test_dbi_clob.rb, test/test_metadata.rb, test/test_oci8.rb + sleep a few seconds and retry if an attempt to connect to + a database server fails and its error code is ORA-12516 + or ORA-12520 in test cases. + 2008-01-12 KUBO Takehiro * lib/oci8.rb.in: fix OCI8#non_blocking = false problem. Once the connection became non-bocking mode, it could Modified: branches/ruby-oci8-1.0/test/config.rb =================================================================== --- branches/ruby-oci8-1.0/test/config.rb 2008-01-15 15:52:14 UTC (rev 242) +++ branches/ruby-oci8-1.0/test/config.rb 2008-02-17 10:31:02 UTC (rev 243) @@ -47,6 +47,29 @@ $test_clob = true end +def do_connect () + begin + yield + rescue OCIError + raise if $!.code != 12516 && $!.code != 12520 + # sleep a few seconds and try again if + # the error code is ORA-12516 or ORA-12520. + # + # ORA-12516 - TNS:listener could not find available handler with + # matching protocol stack + # ORA-12520 - TNS:listener could not find available handler for + # requested type of server + # + # Thanks to Christopher Jones. + # + # Ref: The Underground PHP and Oracle Manual (page 175 in vesion 1.4) + # http://www.oracle.com/technology/tech/php/pdf/underground-php-oracle-manual.pdf + # + sleep(5) + yield + end +end + $env_is_initialized = false def setup_lowapi() if ! $env_is_initialized @@ -58,11 +81,19 @@ $env_is_initialized = true end env = OCIEnv.init() - svc = env.logon($dbuser, $dbpass, $dbname) + svc = do_connect { env.logon($dbuser, $dbpass, $dbname) } stmt = env.alloc(OCIStmt) return env, svc, stmt end +def get_oci_connection() + do_connect { OCI8.new($dbuser, $dbpass, $dbname) } +end + +def get_dbi_connection() + do_connect { DBI.connect("dbi:OCI8:#{$dbname}", $dbuser, $dbpass, 'AutoCommit' => false) } +end + module RUNIT class TestCase def drop_table(table_name) Modified: branches/ruby-oci8-1.0/test/test_break.rb =================================================================== --- branches/ruby-oci8-1.0/test/test_break.rb 2008-01-15 15:52:14 UTC (rev 242) +++ branches/ruby-oci8-1.0/test/test_break.rb 2008-02-17 10:31:02 UTC (rev 243) @@ -37,7 +37,7 @@ end def test_set_blocking_mode - conn = OCI8.new($dbuser, $dbpass, $dbname) + conn = get_oci_connection() conn.non_blocking = true assert_equal(true, conn.non_blocking?) conn.non_blocking = false @@ -48,7 +48,7 @@ end def test_blocking_mode - conn = OCI8.new($dbuser, $dbpass, $dbname) + conn = get_oci_connection() conn.non_blocking = false expect = [] expect[PLSQL_DONE] = TIME_IN_PLSQL @@ -59,7 +59,7 @@ end def test_non_blocking_mode - conn = OCI8.new($dbuser, $dbpass, $dbname) + conn = get_oci_connection() conn.non_blocking = true expect = [] expect[PLSQL_DONE] = "Invalid status" Modified: branches/ruby-oci8-1.0/test/test_dbi.rb =================================================================== --- branches/ruby-oci8-1.0/test/test_dbi.rb 2008-01-15 15:52:14 UTC (rev 242) +++ branches/ruby-oci8-1.0/test/test_dbi.rb 2008-02-17 10:31:02 UTC (rev 243) @@ -7,7 +7,7 @@ class TestDBI < RUNIT::TestCase def setup - @dbh = DBI.connect("dbi:OCI8:#{$dbname}", $dbuser, $dbpass, 'AutoCommit' => false) + @dbh = get_dbi_connection() end def test_select Modified: branches/ruby-oci8-1.0/test/test_dbi_clob.rb =================================================================== --- branches/ruby-oci8-1.0/test/test_dbi_clob.rb 2008-01-15 15:52:14 UTC (rev 242) +++ branches/ruby-oci8-1.0/test/test_dbi_clob.rb 2008-02-17 10:31:02 UTC (rev 243) @@ -7,7 +7,7 @@ class TestDbiCLob < RUNIT::TestCase def setup - @dbh = DBI.connect("dbi:OCI8:#{$dbname}", $dbuser, $dbpass, 'AutoCommit' => false) + @dbh = get_dbi_connection() end def test_insert Modified: branches/ruby-oci8-1.0/test/test_metadata.rb =================================================================== --- branches/ruby-oci8-1.0/test/test_metadata.rb 2008-01-15 15:52:14 UTC (rev 242) +++ branches/ruby-oci8-1.0/test/test_metadata.rb 2008-02-17 10:31:02 UTC (rev 243) @@ -6,7 +6,7 @@ class TestMetadata < RUNIT::TestCase def setup - @conn = OCI8.new($dbuser, $dbpass, $dbname) + @conn = get_oci_connection() end def teardown Modified: branches/ruby-oci8-1.0/test/test_oci8.rb =================================================================== --- branches/ruby-oci8-1.0/test/test_oci8.rb 2008-01-15 15:52:14 UTC (rev 242) +++ branches/ruby-oci8-1.0/test/test_oci8.rb 2008-02-17 10:31:02 UTC (rev 243) @@ -6,7 +6,7 @@ class TestOCI8 < RUNIT::TestCase def setup - @conn = OCI8.new($dbuser, $dbpass, $dbname) + @conn = get_oci_connection() end def teardown From nobody at rubyforge.org Sun Feb 17 09:58:07 2008 From: nobody at rubyforge.org (nobody at rubyforge.org) Date: Sun, 17 Feb 2008 09:58:07 -0500 (EST) Subject: [ruby-oci8-commit] [244] trunk/ruby-oci8: * ext/oci8/object.c, ext/oci8/stmt.c: Message-ID: <20080217145807.43A5418585F0@rubyforge.org> Revision: 244 Author: kubo Date: 2008-02-17 09:58:06 -0500 (Sun, 17 Feb 2008) Log Message: ----------- * ext/oci8/object.c, ext/oci8/stmt.c: change from: switch (fixnum_value) { case INT2FIX(INT_CONSTANT): ....; to: switch (FIX2INT(fixnum_value)) { case INT_CONSTANT: ....; "case INT2FIX(INT_CONSTANT)" confuses astyle. astyle's URL: http://astyle.sourceforge.net * test/config.rb: sleep 5 seconds and retry again when ORA-12516 or ORA-12520. One second was too short on my new linux box. * test/test_oci8.rb: fix a test case for x86_64 linux. Modified Paths: -------------- trunk/ruby-oci8/ChangeLog trunk/ruby-oci8/ext/oci8/object.c trunk/ruby-oci8/ext/oci8/stmt.c trunk/ruby-oci8/test/config.rb trunk/ruby-oci8/test/test_oci8.rb Modified: trunk/ruby-oci8/ChangeLog =================================================================== --- trunk/ruby-oci8/ChangeLog 2008-02-17 10:31:02 UTC (rev 243) +++ trunk/ruby-oci8/ChangeLog 2008-02-17 14:58:06 UTC (rev 244) @@ -1,3 +1,20 @@ +2008-02-17 KUBO Takehiro + * ext/oci8/object.c, ext/oci8/stmt.c: + change from: + switch (fixnum_value) { + case INT2FIX(INT_CONSTANT): + ....; + to: + switch (FIX2INT(fixnum_value)) { + case INT_CONSTANT: + ....; + "case INT2FIX(INT_CONSTANT)" confuses astyle. + astyle's URL: http://astyle.sourceforge.net + * test/config.rb: sleep 5 seconds and retry again when + ORA-12516 or ORA-12520. One second was too short on + my new linux box. + * test/test_oci8.rb: fix a test case for x86_64 linux. + 2008-01-14 KUBO Takehiro * ext/oci8/extconf.rb: add checking code for intern.h, util.h, ruby/util.h, ruby_errinfo and rb_errinfo. Modified: trunk/ruby-oci8/ext/oci8/object.c =================================================================== --- trunk/ruby-oci8/ext/oci8/object.c 2008-02-17 10:31:02 UTC (rev 243) +++ trunk/ruby-oci8/ext/oci8/object.c 2008-02-17 14:58:06 UTC (rev 244) @@ -347,20 +347,20 @@ oci_lc(OCICollTrim(oci8_envhp, oci8_errhp, size - RARRAY_LEN(val), coll)); } for (idx = 0; idx < RARRAY_LEN(val); idx++) { - switch (datatype) { - case INT2FIX(ATTR_NAMED_TYPE): + switch (FIX2INT(datatype)) { + case ATTR_NAMED_TYPE: set_attribute(self, datatype, typeinfo, cb_data->data.ptr, elem_ind_ptr, RARRAY_PTR(val)[idx]); break; default: set_attribute(self, datatype, typeinfo, (void*)&cb_data->data, elem_ind_ptr, RARRAY_PTR(val)[idx]); break; } - switch (datatype) { - case INT2FIX(ATTR_OCINUMBER): - case INT2FIX(ATTR_FLOAT): - case INT2FIX(ATTR_INTEGER): - case INT2FIX(ATTR_BINARY_DOUBLE): - case INT2FIX(ATTR_BINARY_FLOAT): + switch (FIX2INT(datatype)) { + case ATTR_OCINUMBER: + case ATTR_FLOAT: + case ATTR_INTEGER: + case ATTR_BINARY_DOUBLE: + case ATTR_BINARY_FLOAT: elem_ptr = &cb_data->data; break; default: Modified: trunk/ruby-oci8/ext/oci8/stmt.c =================================================================== --- trunk/ruby-oci8/ext/oci8/stmt.c 2008-02-17 10:31:02 UTC (rev 243) +++ trunk/ruby-oci8/ext/oci8/stmt.c 2008-02-17 14:58:06 UTC (rev 244) @@ -480,26 +480,26 @@ static VALUE oci8_stmt_get_stmt_type(VALUE self) { VALUE stmt_type = oci8_get_ub2_attr(DATA_PTR(self), OCI_ATTR_STMT_TYPE); - switch (stmt_type) { - case INT2FIX(OCI_STMT_SELECT): + switch (FIX2INT(stmt_type)) { + case OCI_STMT_SELECT: return oci8_sym_select_stmt; - case INT2FIX(OCI_STMT_UPDATE): + case OCI_STMT_UPDATE: return oci8_sym_update_stmt; - case INT2FIX(OCI_STMT_DELETE): + case OCI_STMT_DELETE: return oci8_sym_delete_stmt; - case INT2FIX(OCI_STMT_INSERT): + case OCI_STMT_INSERT: return oci8_sym_insert_stmt; - case INT2FIX(OCI_STMT_CREATE): + case OCI_STMT_CREATE: return oci8_sym_create_stmt; - case INT2FIX(OCI_STMT_DROP): + case OCI_STMT_DROP: return oci8_sym_drop_stmt; - case INT2FIX(OCI_STMT_ALTER): + case OCI_STMT_ALTER: return oci8_sym_alter_stmt; - case INT2FIX(OCI_STMT_BEGIN): + case OCI_STMT_BEGIN: return oci8_sym_begin_stmt; - case INT2FIX(OCI_STMT_DECLARE): + case OCI_STMT_DECLARE: return oci8_sym_declare_stmt; - case INT2FIX(0): + case 0: return oci8_sym_other; default: rb_bug("unexcepted statement type %d in OCIStmt#stmt_type", FIX2INT(stmt_type)); Modified: trunk/ruby-oci8/test/config.rb =================================================================== --- trunk/ruby-oci8/test/config.rb 2008-02-17 10:31:02 UTC (rev 243) +++ trunk/ruby-oci8/test/config.rb 2008-02-17 14:58:06 UTC (rev 244) @@ -56,7 +56,7 @@ OCI8.new($dbuser, $dbpass, $dbname) rescue OCIError raise if $!.code != 12516 && $!.code != 12520 - # sleep one second and try again if + # sleep a few second and try again if # the error code is ORA-12516 or ORA-12520. # # ORA-12516 - TNS:listener could not find available handler with @@ -69,7 +69,7 @@ # Ref: The Underground PHP and Oracle Manual (page 175 in vesion 1.4) # http://www.oracle.com/technology/tech/php/pdf/underground-php-oracle-manual.pdf # - sleep(1) + sleep(5) OCI8.new($dbuser, $dbpass, $dbname) end @@ -78,7 +78,7 @@ rescue DBI::DatabaseError raise if $!.err != 12516 && $!.err != 12520 # same as get_oci8_connection() - sleep(1) + sleep(5) DBI.connect("dbi:OCI8:#{$dbname}", $dbuser, $dbpass, 'AutoCommit' => false) end Modified: trunk/ruby-oci8/test/test_oci8.rb =================================================================== --- trunk/ruby-oci8/test/test_oci8.rb 2008-02-17 10:31:02 UTC (rev 243) +++ trunk/ruby-oci8/test/test_oci8.rb 2008-02-17 14:58:06 UTC (rev 244) @@ -299,7 +299,7 @@ def test_select_number drop_table('test_table') @conn.exec(< Revision: 245 Author: kubo Date: 2008-02-17 10:29:30 -0500 (Sun, 17 Feb 2008) Log Message: ----------- * Makefile: add format_c_source target to fix indentation by astyle. * ext/oci8/error.c, ext/oci8/lob.c, ext/oci8/metadata.c, ext/oci8/oci8.c, ext/oci8/oci8.h, ext/oci8/oci8lib.c, ext/oci8/ocidatetime.c, ext/oci8/ocinumber.c, ext/oci8/oradate.c, ext/oci8/stmt.c, ext/oci8/xmldb.c: fix indentation by astyle. The command line options are as follows. astyle --style=linux --indent=spaces=4 --brackets=linux ext/oci8/*.[ch] Modified Paths: -------------- trunk/ruby-oci8/ChangeLog trunk/ruby-oci8/Makefile trunk/ruby-oci8/ext/oci8/error.c trunk/ruby-oci8/ext/oci8/lob.c trunk/ruby-oci8/ext/oci8/metadata.c trunk/ruby-oci8/ext/oci8/oci8.c trunk/ruby-oci8/ext/oci8/oci8.h trunk/ruby-oci8/ext/oci8/oci8lib.c trunk/ruby-oci8/ext/oci8/ocidatetime.c trunk/ruby-oci8/ext/oci8/ocinumber.c trunk/ruby-oci8/ext/oci8/oradate.c trunk/ruby-oci8/ext/oci8/stmt.c trunk/ruby-oci8/ext/oci8/xmldb.c Modified: trunk/ruby-oci8/ChangeLog =================================================================== --- trunk/ruby-oci8/ChangeLog 2008-02-17 14:58:06 UTC (rev 244) +++ trunk/ruby-oci8/ChangeLog 2008-02-17 15:29:30 UTC (rev 245) @@ -1,4 +1,15 @@ 2008-02-17 KUBO Takehiro + * Makefile: add format_c_source target to fix indentation by + astyle. + * ext/oci8/error.c, ext/oci8/lob.c, ext/oci8/metadata.c, + ext/oci8/oci8.c, ext/oci8/oci8.h, ext/oci8/oci8lib.c, + ext/oci8/ocidatetime.c, ext/oci8/ocinumber.c, + ext/oci8/oradate.c, ext/oci8/stmt.c, ext/oci8/xmldb.c: + fix indentation by astyle. + The command line options are as follows. + astyle --style=linux --indent=spaces=4 --brackets=linux ext/oci8/*.[ch] + +2008-02-17 KUBO Takehiro * ext/oci8/object.c, ext/oci8/stmt.c: change from: switch (fixnum_value) { Modified: trunk/ruby-oci8/Makefile =================================================================== --- trunk/ruby-oci8/Makefile 2008-02-17 14:58:06 UTC (rev 244) +++ trunk/ruby-oci8/Makefile 2008-02-17 15:29:30 UTC (rev 245) @@ -26,6 +26,9 @@ site-install: $(RUBY) setup.rb install +format_c_source: + astyle --options=none --style=linux --indent=spaces=4 --brackets=linux --suffix=none ext/oci8/*.[ch] + # internal use only dist: -rm -rf ruby-oci8-$(VERSION) Modified: trunk/ruby-oci8/ext/oci8/error.c =================================================================== --- trunk/ruby-oci8/ext/oci8/error.c 2008-02-17 14:58:06 UTC (rev 244) +++ trunk/ruby-oci8/ext/oci8/error.c 2008-02-17 15:29:30 UTC (rev 245) @@ -294,10 +294,10 @@ void oci8_do_raise_init_error(const char *file, int line) { - VALUE msg = rb_str_new2("OCI Library Initialization Error"); - VALUE exc = rb_funcall(eOCIError, oci8_id_new, 1, msg); + VALUE msg = rb_str_new2("OCI Library Initialization Error"); + VALUE exc = rb_funcall(eOCIError, oci8_id_new, 1, msg); - rb_ivar_set(exc, oci8_id_code, rb_ary_new3(1, INT2FIX(-1))); - rb_ivar_set(exc, oci8_id_message, rb_ary_new3(1, msg)); - set_backtrace_and_raise(exc, file, line); + rb_ivar_set(exc, oci8_id_code, rb_ary_new3(1, INT2FIX(-1))); + rb_ivar_set(exc, oci8_id_message, rb_ary_new3(1, msg)); + set_backtrace_and_raise(exc, file, line); } Modified: trunk/ruby-oci8/ext/oci8/lob.c =================================================================== --- trunk/ruby-oci8/ext/oci8/lob.c 2008-02-17 14:58:06 UTC (rev 244) +++ trunk/ruby-oci8/ext/oci8/lob.c 2008-02-17 15:29:30 UTC (rev 245) @@ -412,8 +412,8 @@ newobj = rb_funcall(CLASS_OF(self), oci8_id_new, 1, lob->svc); newlob = DATA_PTR(newobj); if (have_OCILobLocatorAssign_nb && have_OCILobIsTemporary - && OCILobIsTemporary(oci8_envhp, oci8_errhp, lob->base.hp.lob, &is_temporary) == OCI_SUCCESS - && is_temporary) { + && OCILobIsTemporary(oci8_envhp, oci8_errhp, lob->base.hp.lob, &is_temporary) == OCI_SUCCESS + && is_temporary) { oci8_svcctx_t *svcctx = oci8_get_svcctx(lob->svc); rv = OCILobLocatorAssign_nb(svcctx, svcctx->base.hp.svc, oci8_errhp, lob->base.hp.lob, &newlob->base.hp.lob); } else { @@ -467,8 +467,8 @@ bfile_close(lob); oci_lc(OCILobFileSetName(oci8_envhp, oci8_errhp, &lob->base.hp.lob, - RSTRING_ORATEXT(dir_alias), RSTRING_LEN(dir_alias), - RSTRING_ORATEXT(filename), RSTRING_LEN(filename))); + RSTRING_ORATEXT(dir_alias), RSTRING_LEN(dir_alias), + RSTRING_ORATEXT(filename), RSTRING_LEN(filename))); } static VALUE oci8_bfile_initialize(int argc, VALUE *argv, VALUE self) Modified: trunk/ruby-oci8/ext/oci8/metadata.c =================================================================== --- trunk/ruby-oci8/ext/oci8/metadata.c 2008-02-17 14:58:06 UTC (rev 244) +++ trunk/ruby-oci8/ext/oci8/metadata.c 2008-02-17 15:29:30 UTC (rev 245) @@ -1,7 +1,7 @@ /* -*- c-file-style: "ruby"; indent-tabs-mode: nil -*- */ /* * metadata.c - * + * * Copyright (C) 2006-2007 KUBO Takehiro * * implement private methods of classes in OCI8::Metadata module. Modified: trunk/ruby-oci8/ext/oci8/oci8.c =================================================================== --- trunk/ruby-oci8/ext/oci8/oci8.c 2008-02-17 14:58:06 UTC (rev 244) +++ trunk/ruby-oci8/ext/oci8/oci8.c 2008-02-17 15:29:30 UTC (rev 245) @@ -187,10 +187,10 @@ switch (logon_type) { case T_IMPLICIT: rv = OCILogon_nb(svcctx, oci8_envhp, oci8_errhp, &svchp, - RSTRING_ORATEXT(vusername), RSTRING_LEN(vusername), - RSTRING_ORATEXT(vpassword), RSTRING_LEN(vpassword), - NIL_P(vdbname) ? NULL : RSTRING_ORATEXT(vdbname), - NIL_P(vdbname) ? 0 : RSTRING_LEN(vdbname)); + RSTRING_ORATEXT(vusername), RSTRING_LEN(vusername), + RSTRING_ORATEXT(vpassword), RSTRING_LEN(vpassword), + NIL_P(vdbname) ? NULL : RSTRING_ORATEXT(vdbname), + NIL_P(vdbname) ? 0 : RSTRING_LEN(vdbname)); svcctx->base.hp.svc = svchp; svcctx->base.type = OCI_HTYPE_SVCCTX; svcctx->logon_type = T_IMPLICIT; @@ -223,8 +223,8 @@ /* attach to server and set to OCISvcCtx. */ rv = OCIServerAttach_nb(svcctx, svcctx->srvhp, oci8_errhp, - NIL_P(vdbname) ? NULL : RSTRING_ORATEXT(vdbname), - NIL_P(vdbname) ? 0 : RSTRING_LEN(vdbname), OCI_DEFAULT); + NIL_P(vdbname) ? NULL : RSTRING_ORATEXT(vdbname), + NIL_P(vdbname) ? 0 : RSTRING_LEN(vdbname), OCI_DEFAULT); if (rv != OCI_SUCCESS) oci8_raise(oci8_errhp, rv, NULL); oci_lc(OCIAttrSet(svcctx->base.hp.ptr, OCI_HTYPE_SVCCTX, svcctx->srvhp, 0, OCI_ATTR_SERVER, oci8_errhp)); Modified: trunk/ruby-oci8/ext/oci8/oci8.h =================================================================== --- trunk/ruby-oci8/ext/oci8/oci8.h 2008-02-17 14:58:06 UTC (rev 244) +++ trunk/ruby-oci8/ext/oci8/oci8.h 2008-02-17 15:29:30 UTC (rev 245) @@ -17,7 +17,8 @@ #include #include #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif #include #ifdef __cplusplus @@ -86,11 +87,11 @@ #define TO_CHARPTR to_charptr static ALWAYS_INLINE OraText *to_oratext(char *c) { - return (OraText*)c; + return (OraText*)c; } static ALWAYS_INLINE char *to_charptr(OraText *c) { - return (char*)c; + return (char*)c; } #else /* if not gcc, use normal cast. */ @@ -323,7 +324,8 @@ /* xmldb.c */ #ifndef XMLCTX_DEFINED #define XMLCTX_DEFINED -struct xmlctx; typedef struct xmlctx xmlctx; +struct xmlctx; +typedef struct xmlctx xmlctx; #endif #ifndef XML_TYPES typedef struct xmlnode xmlnode; Modified: trunk/ruby-oci8/ext/oci8/oci8lib.c =================================================================== --- trunk/ruby-oci8/ext/oci8/oci8lib.c 2008-02-17 14:58:06 UTC (rev 244) +++ trunk/ruby-oci8/ext/oci8/oci8lib.c 2008-02-17 15:29:30 UTC (rev 245) @@ -273,12 +273,12 @@ tv.tv_usec <<= 1; } if (rv == OCI_ERROR) { - if (oci8_get_error_code(oci8_errhp) == 1013) { - if (have_OCIReset) - OCIReset(svcctx->base.hp.ptr, oci8_errhp); - svcctx->executing_thread = Qnil; - rb_raise(eOCIBreak, "Canceled by user request."); - } + if (oci8_get_error_code(oci8_errhp) == 1013) { + if (have_OCIReset) + OCIReset(svcctx->base.hp.ptr, oci8_errhp); + svcctx->executing_thread = Qnil; + rb_raise(eOCIBreak, "Canceled by user request."); + } } svcctx->executing_thread = Qnil; return rv; Modified: trunk/ruby-oci8/ext/oci8/ocidatetime.c =================================================================== --- trunk/ruby-oci8/ext/oci8/ocidatetime.c 2008-02-17 14:58:06 UTC (rev 244) +++ trunk/ruby-oci8/ext/oci8/ocidatetime.c 2008-02-17 15:29:30 UTC (rev 245) @@ -93,7 +93,7 @@ tz_minute = - tz_minute; } snprintf(buf, sizeof(buf), "%04d-%02d-%02dT%02d:%02d:%02d.%09d%c%02d:%02d", - year, month, day, hour, minute, sec, fsec, sign, + year, month, day, hour, minute, sec, fsec, sign, tz_hour, tz_minute); return rb_funcall(cDateTime, id_parse, 1, rb_str_new2(buf)); } Modified: trunk/ruby-oci8/ext/oci8/ocinumber.c =================================================================== --- trunk/ruby-oci8/ext/oci8/ocinumber.c 2008-02-17 14:58:06 UTC (rev 244) +++ trunk/ruby-oci8/ext/oci8/ocinumber.c 2008-02-17 15:29:30 UTC (rev 245) @@ -240,7 +240,7 @@ /* * call-seq: * OCI8::Math.sin(x) => ocinumber - * + * * Computes the sine of x (expressed in radians). Returns * -1..1. */ @@ -256,7 +256,7 @@ /* * call-seq: * OCI8::Math.tan(x) => ocinumber - * + * * Returns the tangent of x (expressed in radians). */ static VALUE omath_tan(VALUE obj, VALUE radian) @@ -271,7 +271,7 @@ /* * call-seq: * OCI8::Math.acos(x) => ocinumber - * + * * Computes the arc cosine of x. Returns 0..PI. */ static VALUE omath_acos(VALUE obj, VALUE num) @@ -297,7 +297,7 @@ /* * call-seq: * OCI8::Math.asin(x) => ocinumber - * + * * Computes the arc sine of x. Returns 0..PI. */ static VALUE omath_asin(VALUE obj, VALUE num) @@ -323,7 +323,7 @@ /* * call-seq: * OCI8::Math.atan(x) => ocinumber - * + * * Computes the arc tangent of x. Returns -{PI/2} .. {PI/2}. */ static VALUE omath_atan(VALUE obj, VALUE num) @@ -338,7 +338,7 @@ /* * call-seq: * OCI8::Math.cosh(x) => ocinumber - * + * * Computes the hyperbolic cosine of x (expressed in radians). */ static VALUE omath_cosh(VALUE obj, VALUE num) @@ -353,7 +353,7 @@ /* * call-seq: * OCI8::Math.sinh(x) => ocinumber - * + * * Computes the hyperbolic sine of x (expressed in * radians). */ @@ -369,7 +369,7 @@ /* * call-seq: * OCI8::Math.tanh() => ocinumber - * + * * Computes the hyperbolic tangent of x (expressed in * radians). */ @@ -385,7 +385,7 @@ /* * call-seq: * OCI8::Math.exp(x) => ocinumber - * + * * Returns e**x. */ static VALUE omath_exp(VALUE obj, VALUE num) @@ -401,7 +401,7 @@ * call-seq: * OCI8::Math.log(numeric) => ocinumber * OCI8::Math.log(numeric, base_num) => ocinumber - * + * * Returns the natural logarithm of numeric for one argument. * Returns the base base_num logarithm of numeric for two arguments. */ @@ -436,7 +436,7 @@ /* * call-seq: * OCI8::Math.log10(numeric) => ocinumber - * + * * Returns the base 10 logarithm of numeric. */ static VALUE omath_log10(VALUE obj, VALUE num) @@ -456,7 +456,7 @@ /* * call-seq: * OCI8::Math.sqrt(numeric) => ocinumber - * + * * Returns the non-negative square root of numeric. */ static VALUE omath_sqrt(VALUE obj, VALUE num) @@ -663,7 +663,7 @@ rb_raise(rb_eRangeError, "base is negative and exponent part is not an integral value"); oci_lc(OCINumberPower(oci8_errhp, _NUMBER(lhs), &n, &r)); } - return oci8_make_ocinumber(&r); + return oci8_make_ocinumber(&r); } /* @@ -690,7 +690,7 @@ /* * call-seq: * onum.floor => integer - * + * * Returns the largest Integer less than or equal to onum. */ static VALUE onum_floor(VALUE self) @@ -704,7 +704,7 @@ /* * call-seq: * onum.ceil => integer - * + * * Returns the smallest Integer greater than or equal to * onum. */ @@ -720,7 +720,7 @@ * call-seq: * onum.round => integer * onum.round(decplace) => onum - * + * * Rounds onum to the nearest Integer when no argument. * Rounds onum to a specified decimal place decplace when one argument. */ @@ -742,7 +742,7 @@ * call-seq: * onum.truncate => integer * onum.truncate(decplace) => ocinumber - * + * * Truncates onum to the Integer when no argument. * Truncates onum to a specified decimal place decplace when one argument. */ @@ -759,7 +759,7 @@ /* * call-seq: * onum.round_prec(digits) => ocinumber - * + * * Rounds onum to a specified number of decimal digits. * * OCINumber.new(1.234).round_prec(2) #=> 1.2 @@ -777,7 +777,7 @@ /* * call-seq: * onum.to_char(fmt = nil, nls_params = nil) => string - * + * * Returns a string containing a representation of self. * fmt and nls_params are same meanings with * TO_CHAR of Oracle function. @@ -847,7 +847,7 @@ /* * call-seq: * onum.to_s => string - * + * * Returns a string containing a representation of self. */ static VALUE onum_to_s(VALUE self) @@ -858,7 +858,7 @@ /* * call-seq: * onum.to_i => integer - * + * * Returns onm truncated to an Integer. */ static VALUE onum_to_i(VALUE self) @@ -872,9 +872,9 @@ /* * call-seq: * onum.to_f -> float - * + * * Converts onum to a Float. - * + * */ static VALUE onum_to_f(VALUE self) { @@ -887,7 +887,7 @@ /* * call-seq: * onum.to_onum -> onum - * + * */ static VALUE onum_to_onum(VALUE self) { @@ -897,9 +897,9 @@ /* * call-seq: * onum.zero? => true or false - * + * * Returns true if onum is zero. - * + * */ static VALUE onum_zero_p(VALUE self) { @@ -912,9 +912,9 @@ /* * call-seq: * onum.abs -> ocinumber - * + * * Returns the absolute value of onum. - * + * */ static VALUE onum_abs(VALUE self) { @@ -927,7 +927,7 @@ /* * call-seq: * onum.shift(fixnum) => ocinumber - * + * * Returns onum * 10**fixnum */ static VALUE onum_shift(VALUE self, VALUE exp) @@ -1191,7 +1191,7 @@ OCINumber *oci8_get_ocinumber(VALUE num) { - if (!rb_obj_is_kind_of(num, cOCINumber)) { + if (!rb_obj_is_kind_of(num, cOCINumber)) { rb_raise(rb_eTypeError, "invalid argument %s (expect a subclass of %s)", rb_class2name(CLASS_OF(num)), rb_class2name(cOCINumber)); } return _NUMBER(num); Modified: trunk/ruby-oci8/ext/oci8/oradate.c =================================================================== --- trunk/ruby-oci8/ext/oci8/oradate.c 2008-02-17 14:58:06 UTC (rev 244) +++ trunk/ruby-oci8/ext/oci8/oradate.c 2008-02-17 15:29:30 UTC (rev 245) @@ -144,7 +144,7 @@ Data_Get_Struct(rhs, ora_date_t, r); memcpy(l, r, sizeof(ora_date_t)); return lhs; -} +} /* =begin @@ -201,7 +201,7 @@ { ora_date_t *od; VALUE ary[6]; - + Data_Get_Struct(self, ora_date_t, od); ary[0] = INT2FIX(Get_year(od)); ary[1] = INT2FIX(Get_month(od)); @@ -289,13 +289,13 @@ */ static VALUE ora_date_trunc(VALUE self) { - ora_date_t *od; + ora_date_t *od; - Data_Get_Struct(self, ora_date_t, od); - od->hour = 1; - od->minute = 1; - od->second = 1; - return self; + Data_Get_Struct(self, ora_date_t, od); + od->hour = 1; + od->minute = 1; + od->second = 1; + return self; } /* @@ -347,7 +347,7 @@ ora_date_t *od; Data_Get_Struct(self, ora_date_t, od); return rb_str_new((const char*)od, sizeof(ora_date_t)); -} +} static VALUE ora_date_s_load(VALUE klass, VALUE str) { @@ -361,7 +361,7 @@ obj = Data_Make_Struct(cOraDate, ora_date_t, NULL, xfree, od); memcpy(od, RSTRING_PTR(str), sizeof(ora_date_t)); return obj; -} +} /* * bind_oradate Modified: trunk/ruby-oci8/ext/oci8/stmt.c =================================================================== --- trunk/ruby-oci8/ext/oci8/stmt.c 2008-02-17 14:58:06 UTC (rev 244) +++ trunk/ruby-oci8/ext/oci8/stmt.c 2008-02-17 15:29:30 UTC (rev 245) @@ -97,17 +97,17 @@ :position the position of the column. It starts from 1. :type - the type of column. + the type of column. ((|String|)), ((|Fixnum|)), ((|Integer|)), ((|Float|)), ((|Time|)), (()), (()), or ((|OCI_TYPECODE_RAW|)) :length - When the 2nd argument is + When the 2nd argument is * ((|String|)) or ((|OCI_TYPECODE_RAW|)), the max length of fetched data. * otherwise, its value is ignored. :mode - ((|OCI_DEFAULT|)), or ((|OCI_DYNAMIC_FETCH|)). But now available value is + ((|OCI_DEFAULT|)), or ((|OCI_DYNAMIC_FETCH|)). But now available value is ((|OCI_DEFAULT|)) only. Default value is ((|OCI_DEFAULT|)) :return value newly created (()) @@ -533,7 +533,7 @@ * Gets the value of the bind variable. * * In case of binding explicitly, use same key with that of - * OCI8::Cursor#bind_param. A placeholder can be bound by + * OCI8::Cursor#bind_param. A placeholder can be bound by * name or position. If you bind by name, use that name. If you bind * by position, use the position. * Modified: trunk/ruby-oci8/ext/oci8/xmldb.c =================================================================== --- trunk/ruby-oci8/ext/oci8/xmldb.c 2008-02-17 14:58:06 UTC (rev 244) +++ trunk/ruby-oci8/ext/oci8/xmldb.c 2008-02-17 15:29:30 UTC (rev 245) @@ -47,8 +47,7 @@ void *cb[1]; } xmldomcb; -typedef struct xmlctxhead -{ +typedef struct xmlctxhead { ub4 cw_xmlctxhead; /* checkword */ oratext *name_xmlctxhead; /* name for context */ void *cb_xmlctxhead; /* top-level function callbacks */ @@ -351,7 +350,7 @@ attr = XmlDomGetNodeMapItem(xctx, attrs, idx); name = XmlDomGetAttrName(xctx, attr); value = XmlDomGetAttrValue(xctx, attr); - rb_funcall(obj, id_add_attribute, 2, + rb_funcall(obj, id_add_attribute, 2, rb_str_new2_ora(name), value ? rb_str_new2_ora(value) : Qnil); } From nobody at rubyforge.org Wed Feb 27 03:23:39 2008 From: nobody at rubyforge.org (nobody at rubyforge.org) Date: Wed, 27 Feb 2008 03:23:39 -0500 (EST) Subject: [ruby-oci8-commit] [246] trunk/ruby-oci8: Add new feature: Array DML Message-ID: <20080227082339.EC01418585E4@rubyforge.org> Revision: 246 Author: limlian Date: 2008-02-27 03:23:39 -0500 (Wed, 27 Feb 2008) Log Message: ----------- Add new feature: Array DML * lib/oci8/oci8.rb: add three new methods for Array DML to OCI8::Cursor: max_array_size=, bind_param_array and exec_array 1) OCI8::Cursor#max_array_size=: set the maximum array size for OCI8::Cursor#bind_param_array. This method should be called before OCI8::Cursor#bind_param_array 2) OCI8::Cursor#bind_param_array: bind array explicitly. This method is used to bind an array of values to a placeholder embedded in the prepared statement which is to be executed with OCI8::Cursor#exec_array 3) OCI8::Cursor#exec_array: executes the SQL statement assigned the cursor with array bindings. This implementation currently only supports non-data returning statements (INSERT, UPDATE, DELETE but not SELECT). All binding arrays should be the same size and this size will be used as iteration count for OCIStmtExecute() * ext/oci8/stmt.c: add support for Array DML 1) Change the parameters for invoking OCIBindByPos and OCIBindByName because currently we only support Array DML for non-PL/SQL binds. 2) Add a new parameter "Value iteration_count" to function oci8_stmt_execute. This parameter indicates iteration count for OCIStmtExecute. For Non-Array DML, you should set this parameter "nil" 3) Add three new functions: each_value, clear_binds_iterator_proc, oci8_stmt_clear_binds. Those functions are used to clear all binds from OCI8::Cursor. When calling OCI8::Cursor#max_array_size, all the binds will be clean from cursor if instance variable max_array_size of cursor is set before. * test/test_array_dml.rb(added): add test cases for Array DML * test/test_all.rb: call test cases for Array DML Modified Paths: -------------- trunk/ruby-oci8/ChangeLog trunk/ruby-oci8/ext/oci8/stmt.c trunk/ruby-oci8/lib/oci8/oci8.rb trunk/ruby-oci8/test/test_all.rb Added Paths: ----------- trunk/ruby-oci8/test/test_array_dml.rb Modified: trunk/ruby-oci8/ChangeLog =================================================================== --- trunk/ruby-oci8/ChangeLog 2008-02-17 15:29:30 UTC (rev 245) +++ trunk/ruby-oci8/ChangeLog 2008-02-27 08:23:39 UTC (rev 246) @@ -1,3 +1,28 @@ +2008-2-27 Liming Lian + Add new feature: Array DML + * lib/oci8/oci8.rb: add three new methods for Array DML to OCI8::Cursor: + max_array_size=, bind_param_array and exec_array + 1) OCI8::Cursor#max_array_size=: set the maximum array size for OCI8::Cursor#bind_param_array. + This method should be called before OCI8::Cursor#bind_param_array + 2) OCI8::Cursor#bind_param_array: bind array explicitly. This method is used to bind an array of + values to a placeholder embedded in the prepared statement which is to be executed with + OCI8::Cursor#exec_array + 3) OCI8::Cursor#exec_array: executes the SQL statement assigned the cursor with array bindings. + This implementation currently only supports non-data returning statements (INSERT, UPDATE, DELETE + but not SELECT). All binding arrays should be the same size and this size will be used as iteration + count for OCIStmtExecute() + * ext/oci8/stmt.c: add support for Array DML + 1) Change the parameters for invoking OCIBindByPos and OCIBindByName because + currently we only support Array DML for non-PL/SQL binds. + 2) Add a new parameter "Value iteration_count" to function oci8_stmt_execute. + This parameter indicates iteration count for OCIStmtExecute. For Non-Array DML, + you should set this parameter "nil" + 3) Add three new functions: each_value, clear_binds_iterator_proc, oci8_stmt_clear_binds. + Those functions are used to clear all binds from OCI8::Cursor. When calling OCI8::Cursor#max_array_size, + all the binds will be clean from cursor if instance variable max_array_size of cursor is set before. + * test/test_array_dml.rb(added): add test cases for Array DML + * test/test_all.rb: call test cases for Array DML + 2008-02-17 KUBO Takehiro * Makefile: add format_c_source target to fix indentation by astyle. Modified: trunk/ruby-oci8/ext/oci8/stmt.c =================================================================== --- trunk/ruby-oci8/ext/oci8/stmt.c 2008-02-17 15:29:30 UTC (rev 245) +++ trunk/ruby-oci8/ext/oci8/stmt.c 2008-02-27 08:23:39 UTC (rev 246) @@ -19,8 +19,13 @@ static VALUE oci8_sym_declare_stmt; static VALUE oci8_sym_other; static ID id_at_column_metadata; +static ID id_at_actual_array_size; +static ID id_at_max_array_size; +static ID id_each_value; static ID id_at_names; +static ID id_empty_p; static ID id_at_con; +static ID id_clear; static ID id_set; VALUE cOCIStmt; @@ -212,9 +217,9 @@ curelep = &obind->curar_sz; } if (placeholder_ptr == (char*)-1) { - status = OCIBindByPos(stmt->base.hp.stmt, &obind->base.hp.bnd, oci8_errhp, position, obind->valuep, obind->value_sz, bind_class->dty, indp, NULL, 0, obind->maxar_sz, curelep, mode); + status = OCIBindByPos(stmt->base.hp.stmt, &obind->base.hp.bnd, oci8_errhp, position, obind->valuep, obind->value_sz, bind_class->dty, indp, NULL, 0, 0, 0, mode); } else { - status = OCIBindByName(stmt->base.hp.stmt, &obind->base.hp.bnd, oci8_errhp, TO_ORATEXT(placeholder_ptr), placeholder_len, obind->valuep, obind->value_sz, bind_class->dty, indp, NULL, 0, obind->maxar_sz, curelep, mode); + status = OCIBindByName(stmt->base.hp.stmt, &obind->base.hp.bnd, oci8_errhp, TO_ORATEXT(placeholder_ptr), placeholder_len, obind->valuep, obind->value_sz, bind_class->dty, indp, NULL, 0, 0, 0, mode); } if (status != OCI_SUCCESS) { oci8_raise(oci8_errhp, status, stmt->base.hp.stmt); @@ -258,7 +263,7 @@ return rv; } -static VALUE oci8_stmt_execute(VALUE self) +static VALUE oci8_stmt_execute(VALUE self, VALUE iteration_count) { oci8_stmt_t *stmt = DATA_PTR(self); oci8_svcctx_t *svcctx = oci8_get_svcctx(stmt->svc); @@ -270,7 +275,10 @@ iters = 0; mode = OCI_DEFAULT; } else { - iters = 1; + if(!NIL_P(iteration_count)) + iters = NUM2INT(iteration_count); + else + iters = 1; mode = svcctx->is_autocommit ? OCI_COMMIT_ON_SUCCESS : OCI_DEFAULT; } rv = oci8_call_stmt_execute(svcctx, stmt, iters, mode); @@ -326,6 +334,32 @@ return self; } +static VALUE each_value(VALUE obj) +{ + return rb_funcall(obj, id_each_value, 0); +} + +static VALUE clear_binds_iterator_proc(VALUE val, VALUE arg) +{ + if(!NIL_P(val)) { + oci8_base_free((oci8_base_t*)oci8_get_bind(val)); + } + return Qnil; +} + +static VALUE oci8_stmt_clear_binds(VALUE self) +{ + oci8_stmt_t *stmt = DATA_PTR(self); + + if(!RTEST(rb_funcall(stmt->binds, id_empty_p, 0))) + { + rb_iterate(each_value, stmt->binds, clear_binds_iterator_proc, Qnil); + rb_funcall(stmt->binds,id_clear,0); + } + + return self; +} + static VALUE oci8_stmt_do_fetch(oci8_stmt_t *stmt, oci8_svcctx_t *svcctx) { VALUE ary; @@ -597,11 +631,29 @@ */ static VALUE oci8_stmt_aset(VALUE self, VALUE key, VALUE val) { + long max_array_size; + long actual_array_size; + long bind_array_size; + oci8_stmt_t *stmt = DATA_PTR(self); VALUE obj = rb_hash_aref(stmt->binds, key); if (NIL_P(obj)) { return Qnil; /* ?? MUST BE ERROR? */ } + + if(TYPE(val) == T_ARRAY) { + max_array_size = NUM2INT(rb_ivar_get(self, id_at_max_array_size)); + actual_array_size = NUM2INT(rb_ivar_get(self, id_at_actual_array_size)); + bind_array_size = RARRAY_LEN(val); + + if(actual_array_size > 0 && bind_array_size != actual_array_size) { + rb_raise(rb_eRuntimeError, "all binding arrays hould be the same size"); + } + if(bind_array_size <= max_array_size && actual_array_size == 0) { + rb_ivar_set(self, id_at_actual_array_size, INT2NUM(bind_array_size)); + } + } + return rb_funcall(obj, oci8_id_set, 1, val); } @@ -708,14 +760,20 @@ oci8_sym_declare_stmt = ID2SYM(rb_intern("declare_stmt")); oci8_sym_other = ID2SYM(rb_intern("other")); id_at_column_metadata = rb_intern("@column_metadata"); + id_at_actual_array_size = rb_intern("@actual_array_size"); + id_at_max_array_size = rb_intern("@max_array_size"); + id_each_value = rb_intern("each_value"); id_at_names = rb_intern("@names"); id_at_con = rb_intern("@con"); + id_empty_p = rb_intern("empty?"); + id_clear = rb_intern("clear"); id_set = rb_intern("set"); rb_define_private_method(cOCIStmt, "initialize", oci8_stmt_initialize, -1); rb_define_private_method(cOCIStmt, "__define", oci8_define_by_pos, 2); rb_define_private_method(cOCIStmt, "__bind", oci8_bind, 2); - rb_define_private_method(cOCIStmt, "__execute", oci8_stmt_execute, 0); + rb_define_private_method(cOCIStmt, "__execute", oci8_stmt_execute, 1); + rb_define_private_method(cOCIStmt, "__clearBinds", oci8_stmt_clear_binds, 0); rb_define_method(cOCIStmt, "fetch", oci8_stmt_fetch, 0); rb_define_private_method(cOCIStmt, "__paramGet", oci8_stmt_get_param, 1); rb_define_method(cOCIStmt, "type", oci8_stmt_get_stmt_type, 0); Modified: trunk/ruby-oci8/lib/oci8/oci8.rb =================================================================== --- trunk/ruby-oci8/lib/oci8/oci8.rb 2008-02-17 15:29:30 UTC (rev 245) +++ trunk/ruby-oci8/lib/oci8/oci8.rb 2008-02-27 08:23:39 UTC (rev 246) @@ -348,9 +348,12 @@ # true. In contrast with OCI8#exec, it returns true even # though PL/SQL. Use OCI8::Cursor#[] explicitly to get bind # variables. + # + # Pass a "nil" to "__execute" to specify the statement isn't + # an Array DML def exec(*bindvars) bind_params(*bindvars) - __execute() + __execute(nil) case type when :select_stmt define_columns() @@ -361,6 +364,80 @@ end end # exec + # Set the maximum array size for bind_param_array + # + # All the binds will be clean from cursor if instance variable max_array_size is set before + # + # Instance variable actual_array_size holds the size of the arrays users actually binds through bind_param_array + # all the binding arrays are required to be the same size + def max_array_size=(size) + raise "expect positive number for max_array_size." if size.nil? && size <=0 + __clearBinds if !@max_array_size.nil? + @max_array_size = size + @actual_array_size = nil + end # max_array_size= + + # Bind array explicitly + # + # When key is number, it binds by position, which starts from 1. + # When key is string, it binds by the name of placeholder. + # + # The max_array_size should be set before calling bind_param_array + # + # example: + # cursor = conn.parse("INSERT INTO test_table VALUES (:str)") + # cursor.max_array_size = 3 + # cursor.bind_param_array(1, ['happy', 'new', 'year'], String, 30) + # cursor.exec_array + def bind_param_array(key, var_array, type = nil, max_item_length = nil) + raise "please call max_array_size= first." if @max_array_size.nil? + raise "expect array as input param for bind_param_array." if !var_array.nil? && !(var_array.is_a? Array) + raise "the size of var_array should not be greater than max_array_size." if !var_array.nil? && var_array.size > @max_array_size + + if var_array.nil? + raise "all binding arrays should be the same size." unless @actual_array_size.nil? || @actual_array_size == 0 + @actual_array_size = 0 + else + raise "all binding arrays should be the same size." unless @actual_array_size.nil? || var_array.size == @actual_array_size + @actual_array_size = var_array.size if @actual_array_size.nil? + end + + param = {:value => var_array, :type => type, :length => max_item_length, :max_array_size => @max_array_size} + first_non_nil_elem = var_array.nil? ? nil : var_array.find{|x| x!= nil} + + if type.nil? + if first_non_nil_elem.nil? + raise "bind type is not given." + else + type = first_non_nil_elem.class + end + end + + bindclass = OCI8::BindType::Mapping[type] + raise "unsupported dataType: #{type}" if bindclass.nil? + bindobj = bindclass.create(@con, var_array, param, @max_array_size) + __bind(key, bindobj) + self + end # bind_param_array + + # Executes the SQL statement assigned the cursor with array binding + def exec_array + raise "please call max_array_size= first." if @max_array_size.nil? + + if !@actual_array_size.nil? && @actual_array_size > 0 + __execute(@actual_array_size) + else + raise "please set non-nil values to array binding parameters" + end + + case type + when :update_stmt, :delete_stmt, :insert_stmt + row_count + else + true + end + end # exec_array + # Gets the names of select-list as array. Please use this # method after exec. def get_col_names Modified: trunk/ruby-oci8/test/test_all.rb =================================================================== --- trunk/ruby-oci8/test/test_all.rb 2008-02-17 15:29:30 UTC (rev 245) +++ trunk/ruby-oci8/test/test_all.rb 2008-02-27 08:23:39 UTC (rev 246) @@ -17,6 +17,7 @@ require "#{srcdir}/test_datetime" require "#{srcdir}/test_connstr" require "#{srcdir}/test_metadata" +require "#{srcdir}/test_array_dml" # Ruby/DBI begin Added: trunk/ruby-oci8/test/test_array_dml.rb =================================================================== --- trunk/ruby-oci8/test/test_array_dml.rb (rev 0) +++ trunk/ruby-oci8/test/test_array_dml.rb 2008-02-27 08:23:39 UTC (rev 246) @@ -0,0 +1,317 @@ +require 'oci8' +require 'test/unit' +require './config' + +class TestArrayDML < Test::Unit::TestCase + def setup + @conn = get_oci8_connection + end + + def teardown + @conn.logoff + end + + # test inserting arrays with different data types + # including char, varchar2, number, date and so on + def test_array_insert1 + drop_table('test_table') + sql = <<-EOS +CREATE TABLE test_table + (C CHAR(10) NOT NULL, + V VARCHAR2(20), + N NUMBER(10, 2), + D DATE, + INT NUMBER(30), + BIGNUM NUMBER(30)) +STORAGE ( + INITIAL 4k + NEXT 4k + MINEXTENTS 1 + MAXEXTENTS UNLIMITED + PCTINCREASE 0) +EOS + @conn.exec(sql) + cursor = @conn.parse("INSERT INTO test_table VALUES (:C, :V, :N, :D, :INT, :BIGNUM)") + max_array_size = 3 + cursor.max_array_size= max_array_size + + cursor.bind_param_array(1, nil, String) + cursor.bind_param_array(2, nil ,String) + cursor.bind_param_array(3, nil, Fixnum) + cursor.bind_param_array(4, nil, OraDate) + cursor.bind_param_array(5, nil, Integer) + cursor.bind_param_array(6, nil, Bignum) + + c_arr = Array.new + v_arr = Array.new + n_arr = Array.new + d_arr = Array.new + int_arr = Array.new + bignum_arr = Array.new + + 1.upto(30) do |i| + c_arr << format("%10d", i * 10) + v_arr << i.to_s + n_arr << i + d_arr << OraDate.new(2000 + i, 12, 24, 23, 59, 59) + int_arr << i * 11111111111 + bignum_arr << i * 10000000000 + + if i%max_array_size == 0 + cursor[1] = c_arr + cursor[2] = v_arr + cursor[3] = n_arr + cursor[4] = d_arr + cursor[5] = int_arr + cursor[6] = bignum_arr + + r = cursor.exec_array + assert_equal(max_array_size, r) + c_arr.clear + v_arr.clear + n_arr.clear + d_arr.clear + int_arr.clear + bignum_arr.clear + end + end + cursor.close + + cursor = @conn.parse("SELECT * FROM test_table ORDER BY c") + cursor.define(5, Integer) + cursor.define(6, Bignum) + cursor.exec + assert_equal(["C","V","N","D","INT","BIGNUM"], cursor.get_col_names) + 1.upto(30) do |i| + rv = cursor.fetch + assert_equal(format("%10d", i * 10), rv[0]) + assert_equal(i.to_s, rv[1]) + assert_equal(i, rv[2]) + dttm = DateTime.civil(2000 + i, 12, 24, 23, 59, 59, Time.now.utc_offset.to_r/86400) + assert_equal(dttm, rv[3]) + assert_equal(i * 11111111111, rv[4]) + assert_equal(i * 10000000000, rv[5]) + end + assert_nil(cursor.fetch) + drop_table('test_table') + end + + # Raise error when binding arrays are not the same size + def test_array_insert2 + drop_table('test_table') + sql = <<-EOS +CREATE TABLE test_table + (N NUMBER(10, 2) NOT NULL, + V VARCHAR(20)) +EOS + @conn.exec(sql) + cursor = @conn.parse("INSERT INTO test_table VALUES (:N, :V)") + max_array_size = 10 + cursor.max_array_size = max_array_size + cursor.bind_param_array(1, nil, Fixnum) + cursor.bind_param_array(2, nil, String) + n_arr = Array.new + v_arr = Array.new + 1.upto(max_array_size) do |i| + n_arr << i + v_arr << i.to_s if i != max_array_size + end + cursor[1] = n_arr + assert_raise(RuntimeError) { cursor[2] = v_arr } + cursor.close + + drop_table('test_table') + end + + # All binds are clear from cursor after calling "max_array_size=", + # in that case, you have to re-bind the array parameters + # otherwise, an error will be raised. + def test_array_insert3 + drop_table('test_table') + sql = <<-EOS +CREATE TABLE test_table + (N NUMBER(10, 2) NOT NULL, + V VARCHAR(20)) +EOS + @conn.exec(sql) + cursor = @conn.parse("INSERT INTO test_table VALUES (:N, :V)") + cursor.max_array_size = 3 + cursor.bind_param_array(1, [1, 2, 3]) + cursor.bind_param_array(2, ['happy', 'new', 'year']) + assert_nothing_raised() { cursor.exec_array } + cursor.max_array_size = 2 + assert_raise(RuntimeError) { cursor.exec_array } + drop_table('test_table') + end + + # The size of binding arrays are not required to be same as max_array_size. The + # only requirement is that they should be the same size, and the size will be + # used as execution count for OCIStmtExecute. + def test_array_insert4 + drop_table('test_table') + sql = <<-EOS +CREATE TABLE test_table + (N NUMBER(10, 2) NOT NULL, + V VARCHAR(20)) +EOS + @conn.exec(sql) + cursor = @conn.parse("INSERT INTO test_table VALUES (:N, :V)") + max_array_size = 4 + cursor.max_array_size = max_array_size + cursor.bind_param_array(1, nil, Fixnum) + cursor.bind_param_array(2, nil, String) + n_arr = Array.new + v_arr = Array.new + 1.upto( max_array_size - 1 ) do |i| + n_arr << i + v_arr << i.to_s + end + cursor[1] = n_arr + cursor[2] = v_arr + assert_nothing_raised() { cursor.exec_array } + cursor.close + + cursor = @conn.parse("SELECT * FROM test_table ORDER BY N") + cursor.exec + 1.upto( max_array_size - 1 ) do |i| + rv = cursor.fetch + assert_equal(i, rv[0]) + assert_equal(i.to_s, rv[1]) + end + assert_nil(cursor.fetch) + cursor.close + drop_table('test_table') + end + + # Inserting "nil" elements with array dml raises an error + def test_array_insert5 + drop_table('test_table') + sql = <<-EOS +CREATE TABLE test_table + (N NUMBER(10, 2), + V VARCHAR(20)) +EOS + @conn.exec(sql) + cursor = @conn.parse("INSERT INTO test_table VALUES (:N, :V)") + max_array_size = 3 + cursor.max_array_size = max_array_size + cursor.bind_param_array(1, nil, Fixnum) + cursor.bind_param_array(2, nil, String) + assert_raise(RuntimeError) { cursor.exec_array } + cursor.close + drop_table('test_table') + end + + # delete with array bindings + def test_array_delete + drop_table('test_table') + sql = <<-EOS +CREATE TABLE test_table + (N NUMBER(10, 2), + V VARCHAR(20)) +EOS + @conn.exec(sql) + cursor = @conn.parse("INSERT INTO test_table VALUES (:N, :V)") + max_array_size = 10 + cursor.max_array_size = max_array_size + n_arr = Array.new + v_arr = Array.new + 1.upto( max_array_size) do |i| + n_arr << i + v_arr << i.to_s + end + cursor.bind_param_array(1, nil, Fixnum) + cursor.bind_param_array(2, nil, String) + cursor[1] = n_arr + cursor[2] = v_arr + cursor.exec_array + cursor.close + + cursor = @conn.parse("DELETE FROM test_table WHERE N=:N") + cursor.max_array_size = max_array_size + delete_arr = Array.new + 1.upto(max_array_size) do |i| + if i%2 == 0 + delete_arr << i + end + end + cursor.bind_param_array(1, nil, Fixnum) + cursor[1] = delete_arr + cursor.exec_array + cursor.close + + cursor = @conn.parse("SELECT * FROM test_table ORDER BY N") + cursor.exec + 1.upto( max_array_size ) do |i| + if i%2 != 0 + rv = cursor.fetch + assert_equal(rv[0], i) + assert_equal(rv[1], i.to_s) + end + end + assert_nil(cursor.fetch) + cursor.close + + drop_table('test_table') + end + + # update with array bindings + def test_array_update + drop_table('test_table') + sql = <<-EOS +CREATE TABLE test_table + (N NUMBER(10, 2), + V VARCHAR(20)) +EOS + @conn.exec(sql) + cursor = @conn.parse("INSERT INTO test_table VALUES (:N, :V)") + max_array_size = 10 + cursor.max_array_size = max_array_size + n_arr = Array.new + v_arr = Array.new + 1.upto( max_array_size) do |i| + n_arr << i + v_arr << i.to_s + end + cursor.bind_param_array(1, nil, Fixnum) + cursor.bind_param_array(2, nil, String) + cursor[1] = n_arr + cursor[2] = v_arr + cursor.exec_array + cursor.close + + cursor = @conn.parse("UPDATE test_table SET V=:V WHERE N=:N") + cursor.max_array_size = max_array_size + update_arr = Array.new + update_v_arr = Array.new + 1.upto(max_array_size) do |i| + if i%2 == 0 + update_arr << i + update_v_arr << (i * 10).to_s + end + end + cursor.bind_param_array(1, nil, String) + cursor.bind_param_array(2, nil, Fixnum) + cursor[1] = update_v_arr + cursor[2] = update_arr + cursor.exec_array + cursor.close + + cursor = @conn.parse("SELECT * FROM test_table ORDER BY N") + cursor.exec + 1.upto( max_array_size ) do |i| + rv = cursor.fetch + if i%2 != 0 + assert_equal(rv[0], i) + assert_equal(rv[1], i.to_s) + else + assert_equal(rv[0], i) + assert_equal(rv[1], (i * 10).to_s) + end + end + assert_nil(cursor.fetch) + + cursor.close + drop_table('test_table') + end +end