You can subscribe to this list here.
2002 |
Jan
|
Feb
(3) |
Mar
|
Apr
(12) |
May
(11) |
Jun
(2) |
Jul
(37) |
Aug
(3) |
Sep
(24) |
Oct
(31) |
Nov
|
Dec
(4) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2003 |
Jan
(3) |
Feb
(7) |
Mar
|
Apr
(11) |
May
(15) |
Jun
(7) |
Jul
|
Aug
|
Sep
|
Oct
|
Nov
(4) |
Dec
|
2004 |
Jan
|
Feb
|
Mar
|
Apr
(1) |
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
From: Michael N. <mne...@us...> - 2003-05-11 15:27:11
|
Update of /cvsroot/ruby-dbi/src/lib/dbi In directory sc8-pr-cvs1:/tmp/cvs-serv7455 Modified Files: dbi.rb Log Message: class Timestamp: - fraction nil by default - fractions may be of type float (as well as integer) - #to_s do not show fraction if it's nil Index: dbi.rb =================================================================== RCS file: /cvsroot/ruby-dbi/src/lib/dbi/dbi.rb,v retrieving revision 1.38 retrieving revision 1.39 diff -u -r1.38 -r1.39 --- dbi.rb 9 May 2003 19:54:29 -0000 1.38 +++ dbi.rb 11 May 2003 15:27:09 -0000 1.39 @@ -298,15 +298,16 @@ class Timestamp attr_accessor :year, :month, :day attr_accessor :hour, :minute, :second, :fraction - def initialize(year=0, month=0, day=0, hour=0, minute=0, second=0, fraction=0) + + def initialize(year=0, month=0, day=0, hour=0, minute=0, second=0, fraction=nil) case year when ::Time @year, @month, @day = year.year, year.month, year.day - @hour, @minute, @second, @fraction = year.hour, year.min, year.sec, 0 + @hour, @minute, @second, @fraction = year.hour, year.min, year.sec, nil @original_time = year when ::Date @year, @month, @day = year.year, year.month, year.day - @hour, @minute, @second, @fraction = 0, 0, 0, 0 + @hour, @minute, @second, @fraction = 0, 0, 0, nil @original_date = year else @year, @month, @day = year, month, day @@ -314,6 +315,8 @@ end end + def fraction() @fraction || 0 end + def mon() @month end def mon=(val) @month=val end def mday() @day end @@ -324,7 +327,12 @@ def sec=(val) @second=val end def to_s - sprintf("%04d-%02d-%02d %02d:%02d:%02d.%06d", @year, @month, @day, @hour, @minute, @second, @fraction) + s = sprintf("%04d-%02d-%02d %02d:%02d:%02d", @year, @month, @day, @hour, @minute, @second) + if @fraction.nil? + s + else + s + '.' + @fraction.to_s.split('.').last + end end def to_time |
From: Michael N. <mne...@us...> - 2003-05-09 19:54:32
|
Update of /cvsroot/ruby-dbi/src/lib/dbi In directory sc8-pr-cvs1:/tmp/cvs-serv6282 Modified Files: dbi.rb Log Message: zero-pad date/time/timestamps (classes Date/Time/Timestamp method to_s) Index: dbi.rb =================================================================== RCS file: /cvsroot/ruby-dbi/src/lib/dbi/dbi.rb,v retrieving revision 1.37 retrieving revision 1.38 diff -u -r1.37 -r1.38 --- dbi.rb 27 Apr 2003 17:42:56 -0000 1.37 +++ dbi.rb 9 May 2003 19:54:29 -0000 1.38 @@ -1,7 +1,7 @@ # # Ruby/DBI # -# Copyright (c) 2001, 2002 Michael Neumann <ne...@s-...> +# Copyright (c) 2001, 2002, 2003 Michael Neumann <mne...@nt...> # # All rights reserved. # @@ -257,7 +257,7 @@ end def to_s - "#{@year}-#{@month}-#{@day}" + sprintf("%04d-%02d-%02d", @year, @month, @day) end end @@ -290,7 +290,7 @@ end def to_s - "#{@hour}:#{@minute}:#{@second}" + sprintf("%02d:%02d:%02d", @hour, @minute, @second) end end @@ -324,7 +324,7 @@ def sec=(val) @second=val end def to_s - "#{@year}-#{@month}-#{@day} #{@hour}:#{@minute}:#{@second}.#{@fraction}" + sprintf("%04d-%02d-%02d %02d:%02d:%02d.%06d", @year, @month, @day, @hour, @minute, @second, @fraction) end def to_time |
From: Michael N. <mne...@us...> - 2003-04-27 19:18:17
|
Update of /cvsroot/ruby-dbi/src/build In directory sc8-pr-cvs1:/tmp/cvs-serv5986 Modified Files: package.sh Log Message: fixed RAA entry update address Index: package.sh =================================================================== RCS file: /cvsroot/ruby-dbi/src/build/package.sh,v retrieving revision 1.5 retrieving revision 1.6 diff -u -r1.5 -r1.6 --- package.sh 28 Oct 2002 11:18:50 -0000 1.5 +++ package.sh 27 Apr 2003 19:18:13 -0000 1.6 @@ -66,7 +66,7 @@ links http://www.sourceforge.net/account/login.php dialog --msgbox "Finally, update the page at the RAA." 8 40 -w3m "http://www.ruby-lang.org/en/raa-update.rhtml?name=Ruby%2FDBI" +w3m "http://raa.ruby-lang.org/update.rhtml?name=ruby-dbi" # remove work cd .. |
From: Paul D. <pa...@sn...> - 2003-04-27 19:05:43
|
At 20:49 +0200 4/27/03, Michael Neumann wrote: >Paul DuBois wrote: >> At 10:37 -0700 4/27/03, Michael Neumann wrote: >> >Update of /cvsroot/ruby-dbi/src/lib/dbi >> >In directory sc8-pr-cvs1:/tmp/cvs-serv23497 >> > >> >Modified Files: >> > sql.rb >> >Log Message: >> >Fixed bug in DBI::SQL::BasicQuote::Coerce#as_time >> >Mysql time columns (like "13:32:33") could not be converted into >> >DBI::Time objects >> >(thanks to Tim Bates) >> >> Speaking of coercion... >> >> I've noticed that MySQL DATETIME and TIMESTAMP values get converted >> into formats that don't really reflect how MySQL itself displays >> them. For example, a DATETIME value such as '2001-01-01 00:00:00' >> gets coerced to '2001-1-1 0:0:0.0'. Leading zeros are lost, and >> a fraction-of-seconds part is added at the end. >> >> Should this be considered a bug, or just something that MySQL >> users should be aware of, and wary of? > >The string we get from a Mysql database is parsed and converted into >a DBI::Time object. When calling the to_s method of DBI::Time it >is converted back into a string. > >Does Mysql handle '2001-1-1 0:0:0.0' correctly as a DATETIME value? Yes, though this is because it ignores the fractional part (the .0) at the end, which is not part of DATETIME or TIMESTAMP. >And "0:0:0" for TIME values? Yes. >If not, than it's a bug, otherwise not. On the other hand, your questions relate to putting data *into* MySQL. Applications that expect DATETIME values to come *out* of Ruby DBI programs the way that MySQL itself formats them may break. (That is, if a program assumes a string value in CCYY-MM-DD hh:mm:ss format, it cannot break out parts of the value by looking for fixed-length-and-position substrings.) That's why I asked if this behavior is something MySQL users should be wary of. > >When can of course modify the to_s method to output YYYY-MM-DD HH:MM:SS.F, >that's no problem, except perhaps decreased performance (should be ok). There would be no ".F" part for MySQL. > >Regards, > > Michael |
From: Michael N. <mne...@us...> - 2003-04-27 18:57:20
|
Update of /cvsroot/ruby-dbi/src/build In directory sc8-pr-cvs1:/tmp/cvs-serv27901 Modified Files: DBI-VERSIONS USER Log Message: new version Index: DBI-VERSIONS =================================================================== RCS file: /cvsroot/ruby-dbi/src/build/DBI-VERSIONS,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- DBI-VERSIONS 22 Oct 2002 15:28:15 -0000 1.3 +++ DBI-VERSIONS 27 Apr 2003 18:51:55 -0000 1.4 @@ -1,4 +1,5 @@ # All times are in UCT +dbi-0-0-19 2003-04-27 23:00 UTC dbi-0-0-18 2002-10-22 23:00 UTC dbi-0-0-17 2002-10-03 10:00 UTC dbi-0-0-16 2002-07-03 20:10 UTC Index: USER =================================================================== RCS file: /cvsroot/ruby-dbi/src/build/USER,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- USER 2 Oct 2002 18:04:09 -0000 1.1 +++ USER 27 Apr 2003 18:51:55 -0000 1.2 @@ -1,3 +1,4 @@ mneumann:'Michael Neumann <mne...@fa...>' michael:'Michael Neumann <mne...@fa...>' rainer:'Rainer Perl' +pdubois:'Paul Dubois' |
From: Michael N. <mne...@us...> - 2003-04-27 18:57:12
|
Update of /cvsroot/ruby-dbi/src/lib/dbi In directory sc8-pr-cvs1:/tmp/cvs-serv28982 Modified Files: version.rb Log Message: new version Index: version.rb =================================================================== RCS file: /cvsroot/ruby-dbi/src/lib/dbi/version.rb,v retrieving revision 1.4 retrieving revision 1.5 diff -u -r1.4 -r1.5 --- version.rb 22 Oct 2002 15:27:01 -0000 1.4 +++ version.rb 27 Apr 2003 18:54:18 -0000 1.5 @@ -4,6 +4,6 @@ module DBI -VERSION = "0.0.18" +VERSION = "0.0.19" end |
From: Paul D. <pa...@sn...> - 2003-04-27 18:04:20
|
At 10:37 -0700 4/27/03, Michael Neumann wrote: >Update of /cvsroot/ruby-dbi/src/lib/dbi >In directory sc8-pr-cvs1:/tmp/cvs-serv23497 > >Modified Files: > sql.rb >Log Message: >Fixed bug in DBI::SQL::BasicQuote::Coerce#as_time >Mysql time columns (like "13:32:33") could not be converted into >DBI::Time objects >(thanks to Tim Bates) Speaking of coercion... I've noticed that MySQL DATETIME and TIMESTAMP values get converted into formats that don't really reflect how MySQL itself displays them. For example, a DATETIME value such as '2001-01-01 00:00:00' gets coerced to '2001-1-1 0:0:0.0'. Leading zeros are lost, and a fraction-of-seconds part is added at the end. Should this be considered a bug, or just something that MySQL users should be aware of, and wary of? > > >Index: sql.rb >=================================================================== >RCS file: /cvsroot/ruby-dbi/src/lib/dbi/sql.rb,v >retrieving revision 1.13 >retrieving revision 1.14 >diff -u -r1.13 -r1.14 >--- sql.rb 1 Feb 2003 13:45:23 -0000 1.13 >+++ sql.rb 27 Apr 2003 17:37:02 -0000 1.14 >@@ -47,9 +47,9 @@ > end > > def as_time(str) >- return nil if str.nil? >- t = as_timestamp(str) >- DBI::Time.new(t.hour, t.min, t.sec) >+ return nil if str.nil? or str.empty? >+ t = ParseDate.parsedate(str) >+ DBI::Time.new(*t[3,3]) > end > |
From: Michael N. <mne...@us...> - 2003-04-27 17:43:00
|
Update of /cvsroot/ruby-dbi/src/lib/dbi In directory sc8-pr-cvs1:/tmp/cvs-serv29384 Modified Files: dbi.rb Log Message: bug fix in class DBI::Time (wrong named variable) Index: dbi.rb =================================================================== RCS file: /cvsroot/ruby-dbi/src/lib/dbi/dbi.rb,v retrieving revision 1.36 retrieving revision 1.37 diff -u -r1.36 -r1.37 --- dbi.rb 8 Feb 2003 02:26:15 -0000 1.36 +++ dbi.rb 27 Apr 2003 17:42:56 -0000 1.37 @@ -285,7 +285,7 @@ @original_time else t = ::Time.now - ::Time.local(t.year, t.month, t.day, @hour, @min, @sec) + ::Time.local(t.year, t.month, t.day, @hour, @minute, @second) end end |
From: Michael N. <mne...@us...> - 2003-04-27 17:40:40
|
Update of /cvsroot/ruby-dbi/src/doc In directory sc8-pr-cvs1:/tmp/cvs-serv27176 Modified Files: index.rd Log Message: new contributor Index: index.rd =================================================================== RCS file: /cvsroot/ruby-dbi/src/doc/index.rd,v retrieving revision 1.28 retrieving revision 1.29 diff -u -r1.28 -r1.29 --- index.rd 26 Apr 2003 14:53:01 -0000 1.28 +++ index.rd 27 Apr 2003 17:40:36 -0000 1.29 @@ -75,6 +75,9 @@ : Paul DuBois Fixed typos and formatting. Maintains DBD Mysql. +: Tim Bates + Bug fixes for Mysql and DBI + == Database Drivers (DBDs) |
From: Michael N. <mne...@us...> - 2003-04-27 17:37:07
|
Update of /cvsroot/ruby-dbi/src/lib/dbi In directory sc8-pr-cvs1:/tmp/cvs-serv23497 Modified Files: sql.rb Log Message: Fixed bug in DBI::SQL::BasicQuote::Coerce#as_time Mysql time columns (like "13:32:33") could not be converted into DBI::Time objects (thanks to Tim Bates) Index: sql.rb =================================================================== RCS file: /cvsroot/ruby-dbi/src/lib/dbi/sql.rb,v retrieving revision 1.13 retrieving revision 1.14 diff -u -r1.13 -r1.14 --- sql.rb 1 Feb 2003 13:45:23 -0000 1.13 +++ sql.rb 27 Apr 2003 17:37:02 -0000 1.14 @@ -47,9 +47,9 @@ end def as_time(str) - return nil if str.nil? - t = as_timestamp(str) - DBI::Time.new(t.hour, t.min, t.sec) + return nil if str.nil? or str.empty? + t = ParseDate.parsedate(str) + DBI::Time.new(*t[3,3]) end |
From: Michael N. <mne...@us...> - 2003-04-26 14:53:05
|
Update of /cvsroot/ruby-dbi/src/doc In directory sc8-pr-cvs1:/tmp/cvs-serv960 Modified Files: index.rd Log Message: Index: index.rd =================================================================== RCS file: /cvsroot/ruby-dbi/src/doc/index.rd,v retrieving revision 1.27 retrieving revision 1.28 diff -u -r1.27 -r1.28 --- index.rd 22 Jan 2003 10:55:02 -0000 1.27 +++ index.rd 26 Apr 2003 14:53:01 -0000 1.28 @@ -74,6 +74,7 @@ quote/escape_bytea patch for DBD Pg. : Paul DuBois Fixed typos and formatting. + Maintains DBD Mysql. == Database Drivers (DBDs) |
From: Elias K. <el...@us...> - 2003-04-21 18:09:16
|
Update of /cvsroot/ruby-dbi/src/lib/dbd_db2 In directory sc8-pr-cvs1:/tmp/cvs-serv19370 Modified Files: Tag: DB2BLOBS DB2.rb Log Message: DB2 driver support for columns(table) Index: DB2.rb =================================================================== RCS file: /cvsroot/ruby-dbi/src/lib/dbd_db2/DB2.rb,v retrieving revision 1.6.4.1 retrieving revision 1.6.4.2 diff -u -r1.6.4.1 -r1.6.4.2 --- DB2.rb 28 Dec 2002 14:36:30 -0000 1.6.4.1 +++ DB2.rb 21 Apr 2003 18:09:08 -0000 1.6.4.2 @@ -149,6 +149,39 @@ } end + def columns(table) + tabschema, tabname = nil, nil + if md = /([^\.]*)\.(.*)/.match(table) + tabschema, tabname = md[1], md[2] + else + raise 'table name should be in SCHEMA.TABLE notation' + end + query = %{ + SELECT colname, typename, length, scale, default, nulls + FROM syscat.columns + WHERE tabschema = '#{tabschema}' AND tabname = '#{tabname}' + } + if (arr = execute(query).fetch_all) + return arr.collect { |row| + #sql_type, type_name = DB2_to_DBI_type_mapping[row[1]] # FIXME: map column names to constants + ColumnInfo.new({ + 'name' => row[0], + #'type_name' => type_name, + #'sql_type' => sql_type, + 'type_name' => row[1], + 'sql_type' => row[1], + 'precision' => row[2], + 'scale' => row[3], + 'default' => row[4], + 'nullable' => (row[5] == 'Y') + #'indexed' + #'primary' + #'unique' + }) + } + end + end + def ping begin stmt = execute("SELECT 1 FROM SYSCAT.TABLES") @@ -179,8 +212,6 @@ def [](attribute) @attr[attribute] end - - # TODO: method columns(table) def commit rc = SQLEndTran(SQL_HANDLE_DBC, @handle, SQL_COMMIT) |
From: Paul D. <pd...@us...> - 2003-04-02 15:42:59
|
Update of /cvsroot/ruby-dbi/src/lib/dbd_mysql In directory sc8-pr-cvs1:/tmp/cvs-serv13102/lib/dbd_mysql Modified Files: Mysql.rb Log Message: Modify transaction support to use self.do rather than @handler.query so that query execution is routed through the mutex. Index: Mysql.rb =================================================================== RCS file: /cvsroot/ruby-dbi/src/lib/dbd_mysql/Mysql.rb,v retrieving revision 1.20 retrieving revision 1.21 diff -u -r1.20 -r1.21 --- Mysql.rb 8 Feb 2003 02:03:16 -0000 1.20 +++ Mysql.rb 2 Apr 2003 15:42:52 -0000 1.21 @@ -272,7 +272,7 @@ def commit if @have_transactions - @handle.query("COMMIT") + self.do("COMMIT") else raise NotSupportedError end @@ -282,7 +282,7 @@ def rollback if @have_transactions - @handle.query("ROLLBACK") + self.do("ROLLBACK") else raise NotSupportedError end @@ -306,7 +306,7 @@ case attr when 'AutoCommit' if @have_transactions - @handle.query("SET AUTOCOMMIT=" + (value ? "1" : "0")) + self.do("SET AUTOCOMMIT=" + (value ? "1" : "0")) else raise NotSupportedError end |
From: Paul D. <pd...@us...> - 2003-02-08 02:26:19
|
Update of /cvsroot/ruby-dbi/src/lib/dbi In directory sc8-pr-cvs1:/tmp/cvs-serv23097 Modified Files: dbi.rb Log Message: Fix bug in case insensitive driver name lookup on case insensitive filesystems Index: dbi.rb =================================================================== RCS file: /cvsroot/ruby-dbi/src/lib/dbi/dbi.rb,v retrieving revision 1.35 retrieving revision 1.36 diff -u -r1.35 -r1.36 --- dbi.rb 22 Oct 2002 15:06:04 -0000 1.35 +++ dbi.rb 8 Feb 2003 02:26:15 -0000 1.36 @@ -460,8 +460,25 @@ end found ||= driver_name + + # On a filesystem that is not case-sensitive (e.g., HFS+ on Mac OS X), + # the initial require attempt that loads the driver may succeed even + # though the lettercase of driver_name doesn't match the actual + # filename. If that happens, const_get will fail and it become + # necessary to look though the list of constants and look for a + # caseless match. The result of this match provides the constant + # with the proper lettercase -- which can be used to generate the + # driver handle. - dr = DBI::DBD.const_get(found.intern) + dr = nil + begin + dr = DBI::DBD.const_get(found.intern) + rescue NameError + # caseless look for constants to find actual constant + found = found.downcase + found = DBI::DBD.constants.find { |e| e.downcase == found } + dr = DBI::DBD.const_get(found.intern) unless found.nil? + end dbd_dr = dr::Driver.new drh = DBI::DriverHandle.new(dbd_dr) drh.trace(@@trace_mode, @@trace_output) |
From: Paul D. <pd...@us...> - 2003-02-08 02:03:20
|
Update of /cvsroot/ruby-dbi/src/lib/dbd_mysql In directory sc8-pr-cvs1:/tmp/cvs-serv15214 Modified Files: Mysql.rb Log Message: Add transaction support: commit and rollback methods, AutoCommit database handle attribute Index: Mysql.rb =================================================================== RCS file: /cvsroot/ruby-dbi/src/lib/dbd_mysql/Mysql.rb,v retrieving revision 1.19 retrieving revision 1.20 diff -u -r1.19 -r1.20 --- Mysql.rb 8 Feb 2003 01:46:02 -0000 1.19 +++ Mysql.rb 8 Feb 2003 02:03:16 -0000 1.20 @@ -181,10 +181,21 @@ def initialize(handle, attr) super + # check server version to determine transaction capability + ver_str = @handle.get_server_info + major, minor, teeny = ver_str.split(".") + teeny.sub!(/\D*$/, "") # strip any non-numeric suffix if present + server_version = major.to_i*10000 + minor.to_i*100 + teeny.to_i + # It's not until 3.23.17 that SET AUTOCOMMIT, + # BEGIN, COMMIT, and ROLLBACK all are available + @have_transactions = (server_version >= 32317) + # assume the connection begins in AutoCommit mode + @attr['AutoCommit'] = true @mutex = Mutex.new end def disconnect + self.rollback unless @attr['AutoCommit'] @handle.close rescue MyError => err raise DBI::DatabaseError.new(err.message, err.errno) @@ -259,12 +270,24 @@ Statement.new(self, @handle, statement, @mutex) end - # TODO: Raise Error def commit + if @have_transactions + @handle.query("COMMIT") + else + raise NotSupportedError + end + rescue MyError => err + raise DBI::DatabaseError.new(err.message, err.errno) end - # TODO: Raise Error def rollback + if @have_transactions + @handle.query("ROLLBACK") + else + raise NotSupportedError + end + rescue MyError => err + raise DBI::DatabaseError.new(err.message, err.errno) end @@ -277,6 +300,20 @@ else super end + end + + def []=(attr, value) + case attr + when 'AutoCommit' + if @have_transactions + @handle.query("SET AUTOCOMMIT=" + (value ? "1" : "0")) + else + raise NotSupportedError + end + else + raise NotSupportedError + end + @attr[attr] = value end private # ------------------------------------------------- |
From: Paul D. <pd...@us...> - 2003-02-08 01:46:05
|
Update of /cvsroot/ruby-dbi/src/lib/dbd_mysql In directory sc8-pr-cvs1:/tmp/cvs-serv10610 Modified Files: Mysql.rb Log Message: return MySQL error number on exceptions, not just error message Index: Mysql.rb =================================================================== RCS file: /cvsroot/ruby-dbi/src/lib/dbd_mysql/Mysql.rb,v retrieving revision 1.18 retrieving revision 1.19 diff -u -r1.18 -r1.19 --- Mysql.rb 8 Feb 2003 01:37:51 -0000 1.18 +++ Mysql.rb 8 Feb 2003 01:46:02 -0000 1.19 @@ -67,7 +67,7 @@ return Database.new(handle, attr) rescue MyError => err - raise DBI::DatabaseError.new(err.message) + raise DBI::DatabaseError.new(err.message, err.errno) end def data_sources @@ -76,7 +76,7 @@ handle.close return res rescue MyError => err - raise DBI::DatabaseError.new(err.message) + raise DBI::DatabaseError.new(err.message, err.errno) end # Driver-specific functions ------------------------------------------------ @@ -187,7 +187,7 @@ def disconnect @handle.close rescue MyError => err - raise DBI::DatabaseError.new(err.message) + raise DBI::DatabaseError.new(err.message, err.errno) end def ping @@ -202,7 +202,7 @@ def tables @handle.list_tables rescue MyError => err - raise DBI::DatabaseError.new(err.message) + raise DBI::DatabaseError.new(err.message, err.errno) end # Eli Green (fixed up by Michael Neumann) @@ -251,7 +251,7 @@ @handle.affected_rows # return value } rescue MyError => err - raise DBI::DatabaseError.new(err.message) + raise DBI::DatabaseError.new(err.message, err.errno) end @@ -363,13 +363,13 @@ @rows = @handle.affected_rows } rescue MyError => err - raise DBI::DatabaseError.new(err.message) + raise DBI::DatabaseError.new(err.message, err.errno) end def finish @res_handle.free if @res_handle rescue MyError => err - raise DBI::DatabaseError.new(err.message) + raise DBI::DatabaseError.new(err.message, err.errno) end def fill_array(rowdata) @@ -387,7 +387,7 @@ @current_row += 1 fill_array(@res_handle.fetch_row) rescue MyError => err - raise DBI::DatabaseError.new(err.message) + raise DBI::DatabaseError.new(err.message, err.errno) end def fetch_scroll(direction, offset) @@ -431,7 +431,7 @@ } retval rescue MyError => err - raise DBI::DatabaseError.new(err.message) + raise DBI::DatabaseError.new(err.message, err.errno) end def rows |
From: Paul D. <pd...@us...> - 2003-02-08 01:37:55
|
Update of /cvsroot/ruby-dbi/src/lib/dbd_mysql In directory sc8-pr-cvs1:/tmp/cvs-serv8541 Modified Files: Mysql.rb Log Message: port and flag connection parameters must be passed as numbers Index: Mysql.rb =================================================================== RCS file: /cvsroot/ruby-dbi/src/lib/dbd_mysql/Mysql.rb,v retrieving revision 1.17 retrieving revision 1.18 diff -u -r1.17 -r1.18 --- Mysql.rb 8 Feb 2003 00:37:20 -0000 1.17 +++ Mysql.rb 8 Feb 2003 01:37:51 -0000 1.18 @@ -58,6 +58,10 @@ hash['host'] ||= 'localhost' + # these two connection parameters should be passed as numbers + hash['port'] = hash['port'].to_i unless hash['port'].nil? + hash['flag'] = hash['flag'].to_i unless hash['flag'].nil? + handle = ::Mysql.connect(hash['host'], user, auth, hash['database'], hash['port'], hash['socket'], hash['flag']) #handle.select_db(hash['database']) |
From: Paul D. <pd...@us...> - 2003-02-08 00:37:24
|
Update of /cvsroot/ruby-dbi/src/lib/dbd_mysql In directory sc8-pr-cvs1:/tmp/cvs-serv21377 Modified Files: Mysql.rb Log Message: Do not force user to provide database name when connecting Index: Mysql.rb =================================================================== RCS file: /cvsroot/ruby-dbi/src/lib/dbd_mysql/Mysql.rb,v retrieving revision 1.16 retrieving revision 1.17 diff -u -r1.16 -r1.17 --- Mysql.rb 26 Sep 2002 18:37:27 -0000 1.16 +++ Mysql.rb 8 Feb 2003 00:37:20 -0000 1.17 @@ -52,9 +52,9 @@ # connect to database hash = Utils.parse_params(dbname) - if hash['database'].nil? - raise DBI::InterfaceError, "must specify database" - end + #if hash['database'].nil? + # raise DBI::InterfaceError, "must specify database" + #end hash['host'] ||= 'localhost' |
From: Michael N. <mne...@us...> - 2003-02-01 13:51:27
|
Update of /cvsroot/ruby-dbi/src/lib/dbi/test In directory sc8-pr-cvs1:/tmp/cvs-serv21141 Modified Files: testsqlbind.rb Log Message: added comment test Index: testsqlbind.rb =================================================================== RCS file: /cvsroot/ruby-dbi/src/lib/dbi/test/testsqlbind.rb,v retrieving revision 1.5 retrieving revision 1.6 diff -u -r1.5 -r1.6 --- testsqlbind.rb 22 Nov 2001 14:25:38 -0000 1.5 +++ testsqlbind.rb 1 Feb 2003 13:51:24 -0000 1.6 @@ -56,6 +56,12 @@ bind(self, "WHERE c='connected?' AND d=?", [10]) end + def test_comment_dan + sql = %{--Dan's query\n--random comment\nselect column1, column2\nfrom table1\nwhere somevalue = ?} + res = %{--Dan's query\n--random comment\nselect column1, column2\nfrom table1\nwhere somevalue = 10} + assert_equal res, bind(self, sql, [10]) + end + end $last_suite.add_test (TestSqlBind.suite) |
From: Michael N. <mne...@us...> - 2003-02-01 13:45:27
|
Update of /cvsroot/ruby-dbi/src/lib/dbi In directory sc8-pr-cvs1:/tmp/cvs-serv16506 Modified Files: sql.rb Log Message: method BasicBind#tokens: added support for C-style (non-nesting) and Ada/SQL92-style comments Index: sql.rb =================================================================== RCS file: /cvsroot/ruby-dbi/src/lib/dbi/sql.rb,v retrieving revision 1.12 retrieving revision 1.13 diff -u -r1.12 -r1.13 --- sql.rb 6 Feb 2002 14:24:21 -0000 1.12 +++ sql.rb 1 Feb 2003 13:45:23 -0000 1.13 @@ -140,12 +140,27 @@ # This is NOT a full lexer for SQL. It just breaks up the SQL # string enough so that question marks, double question marks and # quoted strings are separated. This is used when binding - # arguments to "?" in the SQL string. Note: comments are not - # handled. + # arguments to "?" in the SQL string. + # + # C-style (/* */) and Ada-style (--) comments are handled. + # Note: Nested C-style comments are NOT handled! # def tokens(sql) - toks = sql.scan(/('([^'\\]|''|\\.)*'|"([^"\\]|""|\\.)*"|\?\??|[^'"?]+)/) - toks.collect {|t| t[0]} + sql.scan(%r{ + ( + -- .* (?# matches "--" style comments to the end of line or string ) + | + /[*] .*? [*]/ (?# matches C-style comments ) + | + ' ( [^'\\] | '' | \\. )* ' (?# match strings surrounded by apostophes ) + | + " ( [^"\\] | "" | \\. )* " (?# match strings surrounded by " ) + | + \?\?? (?# match one or two question marks ) + | + [^-/'"?]+ (?# match all characters except ' " ? - and / ) + + )}x).collect {|t| t.first} end end # module BasicBind |
From: Michael N. <mne...@us...> - 2003-01-22 10:55:05
|
Update of /cvsroot/ruby-dbi/src/doc In directory sc8-pr-cvs1:/tmp/cvs-serv30558 Modified Files: index.rd Log Message: added contributor, added Articles section Index: index.rd =================================================================== RCS file: /cvsroot/ruby-dbi/src/doc/index.rd,v retrieving revision 1.26 retrieving revision 1.27 diff -u -r1.26 -r1.27 --- index.rd 22 Oct 2002 15:25:38 -0000 1.26 +++ index.rd 22 Jan 2003 10:55:02 -0000 1.27 @@ -72,6 +72,8 @@ Submitted several patches and helped with lots of comments; Co-owner of the project. : MoonWolf quote/escape_bytea patch for DBD Pg. +: Paul DuBois + Fixed typos and formatting. == Database Drivers (DBDs) @@ -182,6 +184,9 @@ The DBD specification (how to write a database driver) is lib/dbi/doc/DBD_SPEC or lib/dbi/doc/html/DBD_SPEC.html or available from WWW at ((<URL:http://ruby-dbi.sourceforge.net/DBD_SPEC.html>)). +== Articles + +* ((<Using the Ruby DBI Module|URL:http://www.kitebird.com/articles/ruby-dbi.html>)) by Paul DuBois. == Applications |
From: Michael N. <mne...@us...> - 2003-01-22 10:52:06
|
Update of /cvsroot/ruby-dbi/src/doc In directory sc8-pr-cvs1:/tmp/cvs-serv26656 Modified Files: DBD_SPEC DBI_SPEC Log Message: fixed wrong email address Index: DBD_SPEC =================================================================== RCS file: /cvsroot/ruby-dbi/src/doc/DBD_SPEC,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- DBD_SPEC 22 Jan 2003 10:45:31 -0000 1.2 +++ DBD_SPEC 22 Jan 2003 10:52:03 -0000 1.3 @@ -1,6 +1,6 @@ =begin = DBD Specification Version 0.2.2 (Draft) -by Michael Neumann (ne...@s-...) +by Michael Neumann (mne...@fa...) $Id$ Index: DBI_SPEC =================================================================== RCS file: /cvsroot/ruby-dbi/src/doc/DBI_SPEC,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- DBI_SPEC 22 Jan 2003 10:45:32 -0000 1.2 +++ DBI_SPEC 22 Jan 2003 10:52:03 -0000 1.3 @@ -1,6 +1,6 @@ =begin = DBI Interface Specification Version 0.2.2 (Draft) -by Michael Neumann (ne...@s-...) +by Michael Neumann (mne...@fa...) $Id$ |
From: Michael N. <mne...@us...> - 2003-01-22 10:45:35
|
Update of /cvsroot/ruby-dbi/src/doc In directory sc8-pr-cvs1:/tmp/cvs-serv23382 Modified Files: DBD_SPEC DBI_SPEC Log Message: Fix typos and formatting (by Paul DuBois). Index: DBD_SPEC =================================================================== RCS file: /cvsroot/ruby-dbi/src/doc/DBD_SPEC,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- DBD_SPEC 2 Oct 2002 18:10:37 -0000 1.1 +++ DBD_SPEC 22 Jan 2003 10:45:31 -0000 1.2 @@ -19,9 +19,9 @@ . . -Where "Driver1" and "Driver2" are the names of DBD driver. -For example if you have two drivers installed, "Oracle" and -"Sybase" it would look like: +Where "Driver1" and "Driver2" are DBD driver names. +For example, if you have two drivers installed named "Oracle" and +"Sybase", the layout would look like: DBD/ DBD/Oracle @@ -31,209 +31,213 @@ DBD/Sybase/Sybase.so # <== this is the main driver # has no helper files -When DBI loads a DBD driver it search all "DBD" directories in Ruby's +When DBI loads a DBD driver, it searches all "DBD" directories in Ruby's LOAD_PATH ($:). -Database dependent functions, that should be callable with DBI::func, must +Database dependent functions, that should be callable with (({DBI::func})), must use the prefix "__" before their method names, to prevent nameclashes with further versions of Ruby/DBI! == Driver Name -The DBD driver is simply named after the Database, e.g. Oracle, DB2 etc. -The suffix will normally be ".rb" but can be any other valid suffix, -which Ruby is possible to load, e.g. ".so", ".sl" or ".dll", and depends +The DBD driver is simply named after the Database, e.g., Oracle, DB2, etc. +The suffix normally will be ".rb" but can be any other valid suffix that is +possible for Ruby to load, e.g., ".so", ".sl" or ".dll", and depends for non-Ruby DBD driver on the underlying operating system. When I refer to the driver name, then I speak of the filename without -the suffix, e.g. Oracle or DB2. +the suffix, e.g., Oracle or DB2. -The name specified in the DSN ((-Data Source Name, e.g. "dbi:Oracle:oracle.neumann"-)) +The name specified in the DSN ((-Data Source Name, e.g., "dbi:Oracle:oracle.neumann"-)) must be the same as the driver name. == Classes provided by a DBD A DBD driver has to provide three classes in the namespace -(({DBI::DBD::}))((*DriverName*)) where ((*DriverName*)) is the name of the -driver, e.g. Oracle or DB2. +(({DBI::DBD::}))((*DriverName*)), where ((*DriverName*)) is the name of the +driver, e.g., Oracle or DB2. The three classes must be named (({Driver})), (({Database})) and (({Statement})). == Class Driver This class must inherit from (({DBI::BaseDriver})). -=== Methods which must be provided by (({Driver})) +=== Methods that must be provided by (({Driver})) --- connect( dbname, user, auth, attr ) - Connect to a database and return a newly created (({Database})) object. + Connects to a database and returns a newly created (({Database})) object. -=== Optional methods which can be specified by (({Driver})) +=== Optional methods that can be specified by (({Driver})) --- default_user - Return an array of the form (({['username', 'password']})) which represent - the default user when no user and password was specified. + Returns an array of the form (({['username', 'password']})) which represents + the default user when no username and password were specified. Defaults to (({['', '']})) if not implemented. --- default_attributes - Return a (({Hash})) containing the default attributes which are used - in (({connect})) additional to the ones the user specify. + Returns a (({Hash})) containing the default attributes that are used + in ((<connect>)) in addition to the ones the user specifies. Defaults to (({{}})) (empty hash) if not implemented. --- data_sources - Return an array of all valid DSN this driver can access. + Returns an array of all valid DSNs this driver can access. Defaults to (({[]})) (empty array) if not implemented. --- disconnect_all - Disconnect all connections made with this driver. + Disconnects all connections made with this driver. - Defaults to raise a NotImplementedError. + If this method is not implemented, + the default is to raise a NotImplementedError exception. == Class Database This class must inherit from (({DBI::BaseDatabase})). -=== Methods which must be provided by (({Database})) +=== Methods that must be provided by (({Database})) --- disconnect - Disconnect from database. - But before you have to rollback all outstanding transactions, so - all changes not yet commited get lost. + Disconnects from the database. + But you must first roll back all outstanding transactions, so + all changes not yet committed get lost (are discarded). --- prepare( statement ) - Prepare the SQL ((*statement*)) and return an object of class (({Statement})). + Prepares the SQL ((|statement|)) and returns an object of class (({Statement})). --- ping - Ping the database, and check if the connection is alive. + Pings the database to check whether the connection is alive. This can be implemented by executing a SQL statement like - "SELECT 1 FROM DUAL" for Oracle database, or for other databases - this should be query on a table which normally always exists. + "SELECT 1 FROM DUAL" for Oracle database. + For other databases, + this should be a query on a table that normally always exists. - Return (({true})) if the connection is alive, otherwise (({false})). + Returns (({true})) if the connection is alive, otherwise (({false})). -=== Optional methods which can be specified by (({Database})) +=== Optional methods that can be specified by (({Database})) --- commit --- rollback - Commit or roll back the current transaction. + Commits or rolls back the current transaction. - Defauls to raise a NotSupportedError, so if the database do not implement - transactions (mSQL, mySQL, CSV) do not overwrite this method. + The default is to raise a NotSupportedError exception, so if the database does not implement + transactions (mSQL, MySQL, CSV), do not overwrite this method. --- tables - Return an Array of all tables and views. + Returns an (({Array})) of all tables and views. - Defaults to return the empty Array []. + The default is to return the empty (({Array})) ((({[]}))). --- columns( table ) - Return more information about the columns of table ((*table*)). - Return an Array of Hashes, like Statement#column_info do. - - Defaults to return an empty Array []. + Returns more information about the columns of the table ((|table|)). + Returns an (({Array})) of (({Hash})) objects, like (({Statement#column_info})) does. + + The default is to return an empty (({Array})) ((({[]}))). --- execute( statement, *bindvars ) - Immediate execution (without preparation) of SQL ((*statement*)) - with binding of placeholders to values given in ((*bindvars*)) before. + Immediate execution (without preparation) of SQL ((|statement|)) + after binding the values in ((|bindvars|)) to the placeholders in the statement. - Return a (({Statement})) object. + Returns a (({Statement})) object. - Defaults to the call sequence of Database#prepare(), Statement#bind_params() and - Statement#execute(). + Defaults to the call sequence of (({Database#prepare()})), (({Statement#bind_params()})) and + (({Statement#execute()})). --- do( statement, *bindvars ) - Execution of SQL ((*statement*)) with binding of placeholders to values given - in ((*bindvars*)) before, but without returning a (({Statement})) object. + Execution of SQL ((|statement|)), after binding the values given + in ((|bindvars|)) to the placeholders in the statement, but without returning a (({Statement})) object. So this is used for 'INSERT', 'UPDATE', 'DELETE' as well as for DCL, which - do not return a result-set. + do not return a result set. - Return the RPC (Row Processed Count) or (({nil})) if no RPC is available. + Returns the RPC (Row Processed Count) or (({nil})) if no RPC is available. - Defaults to Database#execute() and Statement#rows() followed by Statement#finish(). + Defaults to (({Database#execute()})) and (({Statement#rows()})) followed by (({Statement#finish()})). --- quote( value ) - Quote the given value ((*value*)) database specific and return the result. + Quotes the given value ((|value|)) in database-specific fashion and returns the result. - NOTE: This method is not really useful, because of Statement#bind_param. + NOTE: This method is not really useful, because of (({Statement#bind_param})). --- []( attr ) - Return value of attribute ((*attr*)). + Returns the value of the attribute ((|attr|)). - Defauls to return the value of (({@attr[attr]})). + The default is to return the value of (({@attr[attr]})). --- []=( attr, value ) - Set value of attribute ((*attr*)) to ((*value*)). - An attribute is e.g. "AutoCommit". - Raise a NotSupportedError, if the database do not support an attribute. + Sets the value of the attribute ((|attr|)) to ((|value|)). + An attribute is, e.g., "AutoCommit". + Raises a NotSupportedError exception if the database does not support an attribute. - The default implementation is to raise a NotSupportedError. + The default implementation is to raise a NotSupportedError exception. == Class Statement This class must inherit from (({DBI::BaseStatement})). -=== Methods which must be provided by (({Statement})) +=== Methods that must be provided by (({Statement})) --- bind_param( param, value, attribs ) - Bind ((|param|)) which is either a (({String})) which is then the name of the - placeholder used in the SQL statement (e.g. Oracle: "SELECT * FROM EMP WHERE ENAME = :ename") - or it is a (({Fixnum})) which is then the number of the placeholder where counting starts at 1. + Binds the value ((|value|)) to a placeholder. + The placeholder is represented by ((|param|)), which is either a + (({String})) representing the name of the + placeholder used in the SQL statement (e.g., Oracle: "SELECT * FROM EMP WHERE ENAME = :ename") + or a (({Fixnum})) that indicates the number of the placeholder. + Placeholder numbers begin at 1. - ((|value|)) is the value which is bound to the placeholder. If ((|value|)) is a (({String})), then the default SQL type is (({VARCHAR})) or (({CHAR})). If ((|value|)) is a (({Fixnum})) or (({Bignum})), the default SQL type is (({INT})). If ((|value|)) is a (({Float})), the default SQL type is (({FLOAT})). - ((*attribs*)) is not yet used in this version but could be a hash containing more information - like parameter type etc. + ((|attribs|)) is not yet used in this version but could be a hash containing more information + like parameter type, etc. --- execute Execute the statement. --- finish Free all the resources for the statement. - After calling (({finish})) no other operation on this + After calling ((<finish>)), no other operation on this statement is valid. --- fetch - Fetch the current row. - Return a (({Array})) containing all column-data or (({nil})) if + Fetches the current row. + Returns an (({Array})) containing all column data or (({nil})) if the last column has been read. - Note: This method should return not a newly created object on each call, - instead you should return one and the same Array object but with + Note: This method should not return a newly created object on each call; + instead, you should return one and the same (({Array})) object but with changed data. --- column_info - Return an (({Array})) of (({Hash}))'s, one for each column. + Returns an (({Array})) of (({Hash})) objects, one for each column. Each (({Hash})) object must have at least one key 'name' which value is the name of that column. - Further possible values are 'sql_type' (integer, e.g. DBI::SQL_INT), + Further possible values are 'sql_type' (integer, e.g., DBI::SQL_INT), 'type_name' (string), 'precision' (= column size), 'scale' (= decimal digits), 'default', 'nullable', 'indexed', 'primary' and 'unique'. --- rows - Return the RPC (Row Processed Count) of the last executed statement, or - (({nil})) if no such exist. + Returns the RPC (Row Processed Count) of the last executed statement, or + (({nil})) if no such exists. -=== Optional methods which can be specified by (({Statement})) +=== Optional methods that can be specified by (({Statement})) --- bind_params( *bindvars ) - Binds the placeholders in the statement to the values of ((|bindvars|)). + Binds the values in ((|bindvars|)) to the placeholders in the statement. - Defaults to calling ((<bind_param>)) for each value, with ((*param*)) starting + Defaults to calling ((<bind_param>)) for each value, with ((|param|)) starting from 1 increasingly. --- cancel - Free any result set resources which were made after a call to (({execute})). - After calling this method, a call to one of the ((*fetch*)) methods is no more valid. + Free any result set resources which were made after a call to ((<execute>)). + After calling this method, calls to any of the ((*fetch*)) methods are no longer valid. - Defaults to do nothing. + The default is to do nothing. --- fetch_scroll( direction, offset ) - ((*direction*)) is one of the following constants: + ((|direction|)) is one of the following constants: * SQL_FETCH_NEXT * SQL_FETCH_PRIOR * SQL_FETCH_FIRST @@ -241,46 +245,46 @@ * SQL_FETCH_ABSOLUTE * SQL_FETCH_RELATIVE - ((*offset*)) is a positive or negativ number (only when SQL_FETCH_RELATIVE is used). + ((|offset|)) is a positive or negative number (only when SQL_FETCH_RELATIVE is used). - By default only SQL_FETCH_NEXT, SQL_FETCH_LAST, SQL_FETCH_RELATIVE (if positive) are - implemented, otherwise it raises NotSupportedError. + By default, only SQL_FETCH_NEXT, SQL_FETCH_LAST, SQL_FETCH_RELATIVE (if positive) are + implemented. Otherwise, this method raises a NotSupportedError exception. - Note: This method should return not a newly created object on each call, - instead you should return one and the same Array object but with + Note: This method should not return a newly created object on each call; + instead, you should return one and the same (({Array})) object but with changed data. --- fetch_many( cnt ) - Return an (({Array})) of the next ((*cnt*)) rows, where a row is itself an (({Array})). + Returns an (({Array})) of the next ((|cnt|)) rows, where a row is itself an (({Array})). - Note: Unlike (({fetch})), this method should return a new Array object. + Note: Unlike ((<fetch>)), this method should return a new (({Array})) object. - If there are no more ((*cnt*)) rows available return the rest. - Return (({nil})) if no rows are available. + If ((|cnt|)) rows are not available, return the rest (as many as are available). + Returns (({nil})) if no rows are available. - Defaults to multiple calls to (({fetch})). + Defaults to multiple calls to ((<fetch>)). --- fetch_all - Return an (({Array})) of all rows which have not yet been fetched, where a row is - itself an (({Array})) (see Statement#fetch_many). + Returns an (({Array})) of all rows that have not yet been fetched, where a row is + itself an (({Array})) (see (({Statement#fetch_many}))). - Note: Unlike (({fetch})), this method should return a new Array object. + Note: Unlike ((<fetch>)), this method should return a new (({Array})) object. - Return (({nil})) if no rows are available. + Returns (({nil})) if no rows are available. - Defaults to multiple calls to (({fetch})). + Defaults to multiple calls to ((<fetch>)). --- []( attr ) - Return value of attribute ((*attr*)). + Returns the value of the attribute ((|attr|)). - Defauls to return the value of (({@attr[attr]})). + The default is to return the value of (({@attr[attr]})). --- []=( attr, value ) - Set value of attribute ((*attr*)) to ((*value*)). - Raise a NotSupportedError, if the database do not support an attribute. + Set the value of the attribute ((|attr|)) to ((|value|)). + Raise a NotSupportedError exception if the database does not support an attribute. - The default implementation is to raise a NotSupportedError. + The default implementation is to raise a NotSupportedError exception. =end Index: DBI_SPEC =================================================================== RCS file: /cvsroot/ruby-dbi/src/doc/DBI_SPEC,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- DBI_SPEC 2 Oct 2002 18:10:37 -0000 1.1 +++ DBI_SPEC 22 Jan 2003 10:45:32 -0000 1.2 @@ -45,14 +45,14 @@ --- SQL_VARBINARY --- SQL_LONGVARBINARY --- SQL_OTHER - Constant representing SQL types. + Constants representing SQL types. === Exceptions Exception classes were "borrowed" from Python API 2.0. --- Warning < RuntimeError - For important warnings like data truncation etc. + For important warnings such as data truncation, etc. --- Error < RuntimeError Base class of all other error exceptions. @@ -64,75 +64,75 @@ --- NotImplementedError < InterfaceError Exception raised if the DBD driver has not specified - a mandantory method (not in Python API 2.0). + a mandatory method (not in Python API 2.0). --- DatabaseError < Error Exception for errors related to the database. - Has three attributes ((|err|)), ((|errstr|)) and ((|state|)). + Has three attributes: ((|err|)), ((|errstr|)) and ((|state|)). --- DataError < DatabaseError Exception for errors due to problems with the processed - data like division by zero, numeric value out of range etc. + data, such ase division by zero, numeric value out of range, etc. --- OperationalError < DatabaseError Exception for errors related to the database's operation which - are not necessarily under the control of the programmer like + are not necessarily under the control of the programmer, such as unexpected disconnect, datasource name not found, transaction - could not be processed, a memory allocation error occured during - processing etc. + could not be processed, a memory allocation error occurred during + processing, etc. --- IntegrityError < DatabaseError Exception raised when the relational integrity of the database - is affected, e.g. a foreign key check fails + is affected, e.g., a foreign key check fails. --- InternalError < DatabaseError Exception raised when the database encounters an internal error, - e.g. the cursor is not valid anymore, the transaction is out of sync. + e.g., the cursor is not valid anymore, the transaction is out of sync. --- ProgrammingError < DatabaseError - Exception raised for programming errors, e.g. table not found + Exception raised for programming errors, e.g., table not found or already exists, syntax error in SQL statement, wrong number of parameters specified, etc. --- NotSupportedError < DatabaseError - Raised if e.g. commit() is called for a database which do not + Raised if, e.g., ((<commit>)) is called for a database that does not support transactions. === Module functions --- DBI.connect( driver_url, user=nil, auth=nil, params=nil ) - Connect to the database specified by ((*driver_url*)), which may + Connect to the database specified by ((|driver_url|)), which may look like "dbi:Oracle:oracle.neumann". - Returns an (({DBI::DatabaseHandle})) object, or if called with code-block, + Returns a (({DBI::DatabaseHandle})) object, or if called with a code-block, calls this block with the new (({DBI::DatabaseHandle})) as parameter and - calls (({disconnect})) after calling the block if it was not yet disconnected by + calls ((<disconnect>)) after calling the block if it was not yet disconnected by the user. --- DBI.available_drivers - Returns an (({Array})) of all available DBD driver. - The strings which represent a DBD driver are partial DSN's - (e.g. "dbi:Oracle:"). + Returns an (({Array})) of all available DBD drivers. + The strings which represent the DBD drivers are partial DSNs + (e.g., "dbi:Oracle:"). --- DBI.data_sources( driver ) - Returns all available DSN's for the ((*driver*)), which - is a partial DSN (e.g. "dbi:Oracle:"). + Returns all available DSNs for the ((|driver|)), which + is a partial DSN (e.g., "dbi:Oracle:"). --- DBI.disconnect_all( driver=nil ) - Disconnects all active connections of ((*driver*)) or - all drivers if ((*driver*)) is (({nil})). + Disconnects all active connections of ((|driver|)) or + all drivers if ((|driver|)) is (({nil})). --- DBI.trace(mode=nil, output=nil) - Set the trace mode for all following created Handles to these values. + Sets the trace mode for all subsequently created Handles to these values. - If a parameter is (({nil})) the value is not changed. + If a parameter is (({nil})), the value is not changed. ((|mode|)) defaults to 2 if it is (({nil})), and ((|output|)) to (({STDERR})) if a value was not - set before. - For ((|mode|)) the values 0, 1, 2 or 3 are allowed. + previously set. + For ((|mode|)), the values 0, 1, 2 or 3 are allowed. - Note: Tracing is only activated, if you load the module "dbi/trace", because tracing currently + Note: Tracing is only activated if you load the module "dbi/trace", because tracing currently depends on AspectR > 0.3.3. == Class DBI::Handle @@ -142,19 +142,19 @@ === Instance Methods --- func( function, *values ) - Calls the driver specific extension function named by + Calls the driver-specific extension function named by ((|function|)) with ((|values|)) as parameters. --- trace(mode=nil, output=nil) - Set the trace mode for this handle as well as for all sub-handles (in the case of DriverHandle and + Sets the trace mode for this handle as well as for all sub-handles (in the case of DriverHandle and DatabaseHandle). - If a parameter is (({nil})) the value is not changed. + If a parameter is (({nil})), the value is not changed. ((|mode|)) defaults to 2 if it is (({nil})), and ((|output|)) to (({STDERR})) if a value was not - set before. - For ((|mode|)) the values 0, 1, 2 or 3 are allowed. + previously set. + For ((|mode|)), the values 0, 1, 2 or 3 are allowed. - Note: Tracing is only activated, if you load the module "dbi/trace", because tracing currently + Note: Tracing is only activated if you load the module "dbi/trace", because tracing currently depends on AspectR > 0.3.3. @@ -176,68 +176,69 @@ --- prepare( stmt ) --- prepare( stmt ) {|statement_handle| aBlock} - Prepare the SQL statement ((|stmt|)) and return a - (({DBI::StatementHandle})) or if called with a code-block - calls the block with the handle as parameter and after that + Prepares the SQL statement ((|stmt|)) and returns a + (({DBI::StatementHandle})), or if called with a code-block, + calls the block with the handle as its parameter and after that calls (({#finish})) onto the handle to free all resources --- execute( stmt, *bindvars ) --- execute( stmt, *bindvars ) {|statement_handle| aBlock} - Executes immediately the SQL statement ((*stmt*)) with binding - the placeholders with values given in ((*bindvars*)) before. + Immediately executes the SQL statement ((|stmt|)) after binding + the values in ((|bindvars|)) to the placeholders in the statement. - Returns a (({DBI::StatementHandle})) or if called with code-block - calls the block with the handle as parameter and after that + Returns a (({DBI::StatementHandle})), or if called with a code-block, + calls the block with the handle as its parameter and after that calls (({#finish})) onto the handle to free all resources. --- do( stmt, *bindvars ) - Same as ((<execute>)) only that no (({DBI::StatementHandle})) is - returned but the RPC (Row Processed Count). + Same as ((<execute>)) except the RPC (Row Processed Count) is returned + rather than a (({DBI::StatementHandle})). --- select_one( stmt, *bindvars) - Executes the statement with binding the values to the parameters and returns the - first row as a reference to a Row object. + Executes the statement after binding the values to the placeholders in the statement, then returns the + first row as a reference to a (({DBI::Row})) object. --- select_all( stmt, *bindvars) - Executes the statement with binding the values to the parameters and returns all - resulting rows. + Executes the statement after binding the values to the parameters, then returns all + resulting rows as an array of (({DBI::Row})) objects. - If called as iterator the passed (({DBI::Row})) objects are only references. + If called as an iterator, the passed (({DBI::Row})) objects are only references. --- tables Returns a list of all tables and views. --- columns( table ) - Get more information about the columns of table ((|table|)). - Returns an array containing for each column one (({DBI::ColumnInfo})) object. + Gets more information about the columns of the table ((|table|)). + Returns an array containing a (({DBI::ColumnInfo})) object for each column + in the table. --- ping Returns (({true})) if the connection is active, otherwise (({false})). - In contranst to ((<connected?>)), ((<ping>)) tests if the connection is + In contrast to ((<connected?>)), ((<ping>)) tests if the connection is still active by executing some SQL or doing something else. --- quote( value ) - Quotes the given value ((*value*)) database specific and returns the result. + Quotes the given value ((|value|)) in database-specific fashion and returns the result. --- commit - Commits current transaction. + Commits the current transaction. --- rollback - Rolls the current transaction back. + Rolls back the current transaction. --- transaction {|database_handle| aBlock} First commits the current transaction, then executes the given block where the parameter is the object itself (the database handle). If the - block raises an exception, then it rolls the transaction - back otherwise commits it. + block raises an exception, then it rolls back the transaction; + otherwise, it commits the transaction. --- [](attr) --- []=(attr) - Sets or gets the attribute ((*attr*)). + Gets or sets the attribute ((|attr|)). An attribute can for example be "AutoCommit", which can be set to - (({true})) or (({false})). Attributes are database dependant. + (({true})) or (({false})). Attributes are database dependent. == Class DBI::StatementHandle @@ -252,85 +253,87 @@ === Instance Methods --- bind_param( param, value, attribs=nil ) - Bind ((*param*)) which is either a (({String})) which is then the name of the - placeholder used in the SQL statement (e.g. Oracle: "SELECT * FROM EMP WHERE ENAME = :ename") - or it is an integer which is then the number of the placeholder where counting starts at 1. + Binds the value ((|value|)) to a placeholder. + The placeholder is represented by ((|param|)), which is either a + (({String})) representing the name of the + placeholder used in the SQL statement (e.g., Oracle: "SELECT * FROM EMP WHERE ENAME = :ename"), + or an integer that indicates the number of the placeholder. + Placeholder numbers begin at 1. - ((*value*)) is the value which is bound to the placeholder. - - ((*attribs*)) is not yet used in this version, but could later be a hash containing more information - like parameter type etc.. + ((|attribs|)) is not yet used in this version, but could later be a hash containing more information + like parameter type, etc. --- execute( *bindvars ) - Execute the statement but before binds the placeholders with ((*bindvars*)). + Executes the statement after binding the values in ((|bindvars|)) to the placeholders in the statement. --- finish Frees the resources for the statement. - After calling ((<finish>)) no other operation on this + After calling ((<finish>)), no other operation on this statement is valid. --- cancel Frees any result set resources which were made after a call - to (({execute})). - After calling this method, a call to one of the ((*fetch*)) methods - is no more valid. + to ((<execute>)). + After calling this method, calls to any of the ((*fetch*)) methods + are no longer valid. --- column_names Returns an (({Array})) of all column names. --- column_info - Returns an (({Array})) containing fore each column one (({DBI::ColumnInfo})) object. + Returns an (({Array})) containing a (({DBI::ColumnInfo})) object for each column + in the result set. --- rows Returns the RPC (Row Processed Count) of the last executed statement, or - (({nil})) if no such exist. + (({nil})) if no such exists. --- fetchable? - Returns true if you can fetch rows using fetch etc.. + Returns (({true})) if you can fetch rows using ((<fetch>)), etc. --- fetch Returns a (({DBI::Row})) object, or (({nil})) if there are no more rows to fetch. - When called as iterator, the block is called for each row - until no more row is available. Each row is passed to the - block as (({DBI::Row})) object. + When called as an iterator, the block is called for each row + until no more rows are available. Each row is passed to the + block as a (({DBI::Row})) object. Note that the returned or passed (({DBI::Row})) object is only a reference and - should be copied (dup) if it is store elsewhere. + should be copied (dup) if it is stored elsewhere. --- each {|row| aBlock } - Same as ((<fetch>)) called as iterator. + Same as ((<fetch>)) called as an iterator. --- fetch_array - Returns the current row as (({Array})) or nil if no more - row is available. + Returns the current row as an (({Array})) or (({nil})) if no more + rows are available. - Can be also called as iterator. + Can also be called as an iterator. --- fetch_hash - Returns the current row as (({Hash})) or nil if no more - row is available. + Returns the current row as a (({Hash})) or (({nil})) if no more + rows are available. - Can be also called as iterator. + Can also be called as an iterator. --- fetch_many( cnt ) - Returns an (({Array})) of the next ((*cnt*)) rows, which are + Returns an (({Array})) of the next ((|cnt|)) rows, which are stored as (({DBI::Row})) objects. Returns the empty array (({[]})) if there are no more rows. --- fetch_all - Same as ((<fetch_many>)) only that all rows are returned. + Same as ((<fetch_many>)) except that all rows are returned. --- fetch_scroll( direction, offset=1 ) - ((*direction*)) is one of the following constants: + ((|direction|)) is one of the following constants: * SQL_FETCH_NEXT * SQL_FETCH_PRIOR * SQL_FETCH_FIRST @@ -338,19 +341,19 @@ * SQL_FETCH_ABSOLUTE * SQL_FETCH_RELATIVE - ((*offset*)) is a positive or negativ number (only when SQL_FETCH_RELATIVE is used). + ((|offset|)) is a positive or negative number (only when SQL_FETCH_RELATIVE is used). - ((<fetch_scroll>)) do not automatically free the result set if no more rows are available - if e.g. you get the last row. + ((<fetch_scroll>)) does not automatically free the result set if no more rows are available, + e.g., if you get the last row. - Returns a (({DBI::Row})) object, if not possible, returns (({nil})). + Returns a (({DBI::Row})) object, or (({nil})) if no row is available. Note that the returned (({DBI::Row})) object is only a reference and should be copied (dup) if it is stored elsewhere. --- [](attr) --- []=(attr) - Sets or gets the attribute ((*attr*)). + Gets or sets the attribute ((|attr|)). =end |
From: Elias K. <el...@us...> - 2002-12-28 14:41:30
|
Update of /cvsroot/ruby-dbi/subprojects/ruby-db2/ext/db2 In directory sc8-pr-cvs1:/tmp/cvs-serv29074 Modified Files: Tag: DB2BLOBS constants.h db2cli.c Log Message: experimental support for BLOBs via SQLBindParameter Index: constants.h =================================================================== RCS file: /cvsroot/ruby-dbi/subprojects/ruby-db2/ext/db2/constants.h,v retrieving revision 1.1 retrieving revision 1.1.2.1 diff -u -r1.1 -r1.1.2.1 --- constants.h 5 Sep 2002 09:57:13 -0000 1.1 +++ constants.h 28 Dec 2002 14:41:26 -0000 1.1.2.1 @@ -5,6 +5,7 @@ rb_define_const(mDB2CLI, "SQL_ERROR", INT2NUM(SQL_ERROR)); rb_define_const(mDB2CLI, "SQL_NO_DATA_FOUND", INT2NUM(SQL_NO_DATA_FOUND)); rb_define_const(mDB2CLI, "SQL_NULL_DATA", INT2NUM(SQL_NULL_DATA)); +rb_define_const(mDB2CLI, "SQL_NEED_DATA", INT2NUM(SQL_NEED_DATA)); rb_define_const(mDB2CLI, "SQL_HANDLE_ENV", INT2NUM(SQL_HANDLE_ENV)); rb_define_const(mDB2CLI, "SQL_HANDLE_DBC", INT2NUM(SQL_HANDLE_DBC)); rb_define_const(mDB2CLI, "SQL_HANDLE_STMT", INT2NUM(SQL_HANDLE_STMT)); @@ -87,4 +88,7 @@ rb_define_const(mDB2CLI, "SQL_DESC_LOCAL_TYPE_NAME", INT2NUM(SQL_DESC_LOCAL_TYPE_NAME)); rb_define_const(mDB2CLI, "SQL_DESC_NUM_PREC_RADIX", INT2NUM(SQL_DESC_NUM_PREC_RADIX)); rb_define_const(mDB2CLI, "SQL_DESC_UNNAMED", INT2NUM(SQL_DESC_UNNAMED)); - +// parameter direction +rb_define_const(mDB2CLI, "SQL_PARAM_INPUT", INT2NUM(SQL_PARAM_INPUT)); +rb_define_const(mDB2CLI, "SQL_PARAM_OUTPUT", INT2NUM(SQL_PARAM_OUTPUT)); +rb_define_const(mDB2CLI, "SQL_PARAM_INPUT_OUTPUT", INT2NUM(SQL_PARAM_INPUT_OUTPUT)); Index: db2cli.c =================================================================== RCS file: /cvsroot/ruby-dbi/subprojects/ruby-db2/ext/db2/db2cli.c,v retrieving revision 1.2 retrieving revision 1.2.2.1 diff -u -r1.2 -r1.2.2.1 --- db2cli.c 20 Dec 2002 10:04:58 -0000 1.2 +++ db2cli.c 28 Dec 2002 14:41:27 -0000 1.2.2.1 @@ -8,7 +8,7 @@ * Contributors: * * Songsu Yun (yu...@us...) - * + * Elias Karakoulakis (ek...@na...) * * Copyright (c) 2001, 2002 by Michael Neumann. * @@ -36,7 +36,25 @@ system (in Germany correct would be "5,7"). Fault of Linux ???? **********************************************************************/ - +/********************************************************************** + A little note about memory management: + ====================================================================== + When the old and the new programming paradigms (C & Ruby) are forced + to cooperate (as in our case), strange things can happen in the memory + management arena. + In detail: we need to be able to allocate memory from C routines AND + free them from the CLI AND Ruby's Garbage cleaner. Otherwise, memory + leaks will cause your available memory to drain. + We can't just use Ruby variables to store our intermediate buffers, + since the CLI will fiddle with them, regardless of any GC in place. + So we use a hash class variable, 'param_buffers' that contains all + memory buffer pointers allocated for CLI's use. Its form is: + key: Object.id of object holding buffers e.g. a Statement + value: array of pointer pairs (buffer, buffer size), one for each + parameter bound to this statement. + all buffers for a statement are freed whenever a new statement is + initialized, OR whenever a Statement object gets finalized from GC. +**********************************************************************/ /* Includes */ #include <stdio.h> @@ -44,8 +62,6 @@ #include "sqlcli1.h" #include "ruby.h" - - /* Macros */ #define TO_C_INT(val) NUM2INT(val) #define TO_RUBY_INT(val) INT2NUM(val) @@ -55,11 +71,11 @@ #define MIN(a,b) ((a) < (b) ? (a) : (b)) /* Global Variables */ -static VALUE mDB2CLI; +static VALUE mDB2CLI, cDBI_Binary; static VALUE cDate, cTime, cTimestamp; static VALUE objNull; /* object for a SQL NULL value */ - - +static VALUE param_buffers; +static VALUE paranoid_debug; /* Functions */ @@ -445,7 +461,6 @@ (SQLSMALLINT*) &nullable ); - retval = rb_ary_new3( 5, TO_RUBY_INT(rc), @@ -1039,51 +1054,177 @@ } -/******************************************************* - SQLBindParameter added by yun - ======================================================= - PARAMS: statement_handle : Integer, - parameter_number : Integer, - parameter_type : Integer, - parameter_size : Integer, - decimal_digits : Integer - parameter_value : String, - - RETURNS: rc : Integer - - Note - ValueType parameter to SQLBindParameter call is set to - SQL_C_CHAR. DB2 will convert it to proper type - based on ParameterType parameter(parameter_type) -********************************************************/ - -static VALUE -db2_SQLBindParameter(self, statement_handle, parameter_number, parameter_type, - parameter_size, decimal_digits, parameter_value) - VALUE self; - VALUE statement_handle, parameter_number, parameter_type, parameter_value; - VALUE parameter_size, decimal_digits; -{ - SQLRETURN rc; - - MUST_BE_STRING(parameter_value); - rc = SQLBindParameter( - (SQLHSTMT) TO_C_INT(statement_handle), - (SQLUSMALLINT) TO_C_INT(parameter_number), - (SQLSMALLINT) SQL_PARAM_INPUT, /* support input parameter only */ - (SQLSMALLINT) SQL_C_CHAR, /* ValueType. Always string */ - (SQLSMALLINT) TO_C_INT(parameter_type), /* SQL data type of the parameter */ - (SQLUINTEGER) TO_C_INT(parameter_size), /* column size */ - (SQLSMALLINT) TO_C_INT(decimal_digits), /* decimal digits */ - (SQLCHAR *FAR) RSTRING(parameter_value)->ptr, /* parameter value pointer */ - (SQLINTEGER) RSTRING(parameter_value)->len, /* buffer length */ - (SQLINTEGER *FAR) &(RSTRING(parameter_value)->len) /*StrLen */ - ); - - return TO_RUBY_INT(rc); +//~ /******************************************************* + //~ SQLBindParameter added by yun + //~ ======================================================= + //~ PARAMS: statement_handle : Integer, + //~ parameter_number : Integer, + //~ parameter_type : Integer, + //~ parameter_size : Integer, + //~ decimal_digits : Integer + //~ parameter_value : String, + + //~ RETURNS: rc : Integer + + //~ Note + //~ ValueType parameter to SQLBindParameter call is set to + //~ SQL_C_CHAR. DB2 will convert it to proper type + //~ based on ParameterType parameter(parameter_type) +//~ ********************************************************/ + +//~ static VALUE +//~ db2_SQLBindParameter(self, statement_handle, parameter_number, parameter_type, + //~ parameter_size, decimal_digits, parameter_value) + //~ VALUE self; + //~ VALUE statement_handle, parameter_number, parameter_type, parameter_value; + //~ VALUE parameter_size, decimal_digits; +//~ { + //~ SQLRETURN rc; + + //~ MUST_BE_STRING(parameter_value); + //~ rc = SQLBindParameter( + //~ (SQLHSTMT) TO_C_INT(statement_handle), + //~ (SQLUSMALLINT) TO_C_INT(parameter_number), + //~ (SQLSMALLINT) SQL_PARAM_INPUT, /* support input parameter only */ + //~ (SQLSMALLINT) SQL_C_CHAR, /* ValueType. Always string */ + //~ (SQLSMALLINT) TO_C_INT(parameter_type), /* SQL data type of the parameter */ + //~ (SQLUINTEGER) TO_C_INT(parameter_size), /* column size */ + //~ (SQLSMALLINT) TO_C_INT(decimal_digits), /* decimal digits */ + //~ (SQLCHAR *FAR) RSTRING(parameter_value)->ptr, /* parameter value pointer */ + //~ (SQLINTEGER) RSTRING(parameter_value)->len, /* buffer length */ + //~ (SQLINTEGER *FAR) &(RSTRING(parameter_value)->len) /*StrLen */ + //~ ); + + //~ return TO_RUBY_INT(rc); +//~ } + +/******************************************************* + SQLBindParameter: bind a buffer to a parameter marker + ======================================================= + PARAMS: SQLHSTMT StatementHandle (in) + SQLUSMALLINT ParameterNumber (in) + SQLSMALLINT InputOutputType (in) + SQLSMALLINT ValueType (in) + SQLSMALLINT ParameterType (in) + SQLUINTEGER ColumnSize (in) + SQLSMALLINT DecimalDigits (in) + SQLPOINTER ParameterValuePtr (in DEFERRED/out DEFERRED) + SQLINTEGER BufferLength, (in) + SQLINTEGER *FAR StrLen_or_IndPtr (in DEFERRED/out DEFERRED) + RETURNS: rc : Integer + ParameterValuePtr: Integer + StrLen_or_IndPtr: Integer +********************************************************/ +static VALUE +db2_SQLBindParameter(self, hstmt, param_id, param_direction, db2_sql_type, ruby_value) + VALUE self, hstmt, param_id, param_direction, db2_sql_type, ruby_value; +{ + SQLSMALLINT fCType, ibScale=0; + SQLUINTEGER cbColDef = 0; + SQLPOINTER rgbValue; + SQLINTEGER* pcbValue = ALLOC_N(SQLINTEGER, 1); + SQLRETURN rc; + VALUE tmp, id, hash, buffers; + int paramType; + + if ((SQL_PARAM_OUTPUT == TO_C_INT(param_direction)) || + (SQL_PARAM_INPUT_OUTPUT == TO_C_INT(param_direction))) { + // TODO: alloc buffer for returned value + } + + if (NIL_P(ruby_value)) { // parameter is null + *pcbValue = SQL_NULL_DATA; + rgbValue = NULL; + fCType = SQL_C_DEFAULT; + paramType = SQL_NULL_DATA; + } else { + if (NIL_P(db2_sql_type)) { + rb_raise(rb_eTypeError, "DB2 CLI: db2_sql_type must be set to a valid type when a not-nil value is bound"); + } + paramType = TO_C_INT(db2_sql_type); + switch (TYPE(ruby_value)) { + case T_OBJECT: + if (rb_obj_is_instance_of(ruby_value, cDBI_Binary)) { + ruby_value = rb_funcall(ruby_value, rb_intern("to_s"), 0); + } else { + rb_raise(rb_eTypeError, "DB2 CLI: large objects must be wrapped inside a DBI::Binary instance"); + } + fCType = SQL_C_BINARY; + *pcbValue = RSTRING(ruby_value)->len; + rgbValue = ALLOC_N(char, (*pcbValue)); + memcpy(rgbValue, RSTRING(ruby_value)->ptr, *pcbValue); + break; + case T_FIXNUM: + fCType = SQL_C_LONG; + *pcbValue = sizeof(long); + rgbValue = ALLOC(long); + *((long *)rgbValue) = (long) FIX2INT(ruby_value); + break; + case T_BIGNUM: case T_FLOAT: // dirty hack + ruby_value = rb_funcall(ruby_value, rb_intern("to_s"), 0); + case T_STRING: + fCType = SQL_C_CHAR; + *pcbValue = RSTRING(ruby_value)->len + 1; // to accomodate the terminating nil + rgbValue = ALLOC_N(char, (*pcbValue)); + memcpy(rgbValue, RSTRING(ruby_value)->ptr, *pcbValue); + break; + default: + rb_raise(rb_eTypeError, "Cannot bind parameter to this kind of value!"); + } + } + + if (paranoid_debug) { + printf("SQLBindParameter: self=%x, hstmt=%x, param_id=%d, rgbValue=0x%08x, pcbValue=0x%08x, indPtr=%d\n", self, TO_C_INT(hstmt), TO_C_INT(param_id), rgbValue, pcbValue, ((SQLINTEGER) *pcbValue)); + } + + rc = SQLBindParameter( + (SQLHSTMT) TO_C_INT(hstmt), // StatementHandle + (SQLUSMALLINT) TO_C_INT(param_id), // ParameterNumber + (SQLSMALLINT) TO_C_INT(param_direction), // InputOutputType + (SQLSMALLINT) fCType, // ValueType + (SQLSMALLINT) paramType, // ParameterType + (SQLUINTEGER) cbColDef, // ColumnSize + (SQLSMALLINT) ibScale, // DecimalDigits + (SQLPOINTER) rgbValue, // ParameterValuePtr + (SQLINTEGER) sizeof(rgbValue), /* cbValueMax */ // BufferLength + (SQLINTEGER *FAR) pcbValue + ); + + // store buffer addresses for later disposal + //if (paranoid_debug) printf("param_buffers: %s\n", RSTRING(rb_funcall(param_buffers, rb_intern("inspect"), 0))->ptr); + id = rb_funcall(self, rb_intern("__id__"), 0); + if (NIL_P(buffers = rb_hash_aref(param_buffers, id))) { + buffers = rb_ary_new(); // create array of parameter buffer pointers + rb_hash_aset(param_buffers, id, buffers); + } + rb_ary_store(buffers, TO_C_INT(param_id)-1, rb_ary_new3( + 2, TO_RUBY_INT((int) rgbValue), TO_RUBY_INT((int) pcbValue) + )); + if (paranoid_debug) printf("param_buffers: %s\n", RSTRING(rb_funcall(param_buffers, rb_intern("inspect"), 0))->ptr); + return TO_RUBY_INT(rc); +} + +// free parameter buffers +static VALUE +db2_free_bound_params(VALUE self, VALUE id) { + VALUE arr, pointer_pair, p1, p2; + if (paranoid_debug) printf("DB2CLI: cleaning up id %d, buffers: %s\n", TO_C_INT(id), RSTRING(rb_funcall(param_buffers, rb_intern("inspect"), 0))->ptr); + if (!NIL_P(arr = rb_hash_aref(param_buffers, id))) { + if (paranoid_debug) printf("DB2CLI: found hash key\n"); + while (!NIL_P(pointer_pair = rb_ary_pop(arr))) { + p1 = rb_ary_pop(pointer_pair); + p2 = rb_ary_pop(pointer_pair); + free((void*) TO_C_INT(p1)); + free((void*) TO_C_INT(p2)); + if (paranoid_debug) printf("DB2CLI: freed buffers 0x%08x, 0x%08x\n", TO_C_INT(p1), TO_C_INT(p2)); + } + if (paranoid_debug) printf("DB2CLI: deleting key %d from hash\n", TO_C_INT(id)); + rb_funcall(param_buffers, rb_intern("delete"), 1, id); + } + if (paranoid_debug) printf("DB2CLI: buffers AFTER cleanup: %s\n", RSTRING(rb_funcall(param_buffers, rb_intern("inspect"), 0))->ptr); + return TO_RUBY_INT(0); } - /******************************************************* SQLGetCursorName added by yun ======================================================= @@ -1144,11 +1285,65 @@ return TO_RUBY_INT(rc); } + + +/******************************************************* + SQLParamData added by ekarak + ======================================================= + PARAMS: SQLHSTMT StatementHandle, + SQLPOINTER FAR *ValuePtrPtr + RETURNS: rc : Integer +********************************************************/ +static VALUE +db2_SQLParamData(self, hstmt, valueptrptr) +VALUE self, hstmt, valueptrptr; +{ + SQLRETURN rc; + + rc = SQLParamData( + (SQLHSTMT) TO_C_INT(hstmt), + (SQLPOINTER FAR*) TO_C_INT(valueptrptr) + ); + + return TO_RUBY_INT(rc); +} + +/******************************************************* + SQLPutData added by ekarak + ======================================================= + PARAMS: SQLHSTMT StatementHandle + SQLPOINTER DataPtr + SQLINTEGER StrLen_or_Ind + RETURNS: rc : Integer +********************************************************/ +static VALUE +db2_SQLPutData(self, hstmt, dataptr, strlen_or_ind) +VALUE self, hstmt, dataptr, strlen_or_ind; +{ + SQLRETURN rc; + + rc = SQLPutData( + (SQLHSTMT) TO_C_INT(hstmt), + (SQLPOINTER) TO_C_INT(dataptr), + (SQLINTEGER) TO_C_INT(strlen_or_ind) + ); + + return TO_RUBY_INT(rc); +} + /* Init */ void Init_db2cli() { + rb_require("dbi"); + // FIXME: is eval_string the most efficient way? mDB2CLI = rb_eval_string("DB2CLI"); - + cDBI_Binary = rb_eval_string("DBI::Binary"); + + param_buffers = rb_hash_new(); + rb_cv_set(mDB2CLI, "@@param_buffers", param_buffers); // store it as a class variable so that GC never frees it + printf("INIT: param_buffers: 0x%08x\n", param_buffers); + paranoid_debug = RTEST(rb_gv_get("$PARANOID_DEBUG")); + #include "constants.h" rb_define_module_function(mDB2CLI, "SQLAllocHandle", db2_SQLAllocHandle, 2); @@ -1178,15 +1373,17 @@ rb_define_module_function(mDB2CLI, "SQLGetDiagRec", db2_SQLGetDiagRec, 4); rb_define_module_function(mDB2CLI, "SQLTables", db2_SQLTables, 5); - rb_define_module_function(mDB2CLI, "SQLBindParameter", db2_SQLBindParameter, 6); + rb_define_module_function(mDB2CLI, "SQLBindParameter", db2_SQLBindParameter, 5); rb_define_module_function(mDB2CLI, "SQLSetCursorName", db2_SQLSetCursorName, 2); rb_define_module_function(mDB2CLI, "SQLGetCursorName", db2_SQLGetCursorName, 1); + rb_define_module_function(mDB2CLI, "SQLParamData", db2_SQLParamData, 2); + rb_define_module_function(mDB2CLI, "SQLPutData", db2_SQLPutData, 3); + // + rb_define_singleton_method(mDB2CLI, "free_bound_params",db2_free_bound_params,1); + /* Datatype classes or objects */ - cDate = rb_eval_string("DB2CLI::Date"); cTime = rb_eval_string("DB2CLI::Time"); cTimestamp = rb_eval_string("DB2CLI::Timestamp"); objNull = rb_eval_string("DB2CLI::Null"); } - - |
From: Elias K. <el...@us...> - 2002-12-28 14:36:36
|
Update of /cvsroot/ruby-dbi/src/lib/dbd_db2 In directory sc8-pr-cvs1:/tmp/cvs-serv27888/lib/dbd_db2 Modified Files: Tag: DB2BLOBS DB2.rb Log Message: experimental support for BLOBs via SQLBindParameter Index: DB2.rb =================================================================== RCS file: /cvsroot/ruby-dbi/src/lib/dbd_db2/DB2.rb,v retrieving revision 1.6 retrieving revision 1.6.4.1 diff -u -r1.6 -r1.6.4.1 --- DB2.rb 3 Jul 2002 16:48:35 -0000 1.6 +++ DB2.rb 28 Dec 2002 14:36:30 -0000 1.6.4.1 @@ -29,6 +29,8 @@ # # $Id$ # +# Severly hacked by Elias Karakoulakis <ek...@na...> +# to support large object functionality require 'db2/db2cli.rb' @@ -36,7 +38,7 @@ module DBD module DB2 -USED_DBD_VERSION = "0.1" +USED_DBD_VERSION = "0.2.2" module Util include DB2CLI @@ -44,11 +46,16 @@ private def rc_ok(rc) - rc == SQL_SUCCESS or rc == SQL_SUCCESS_WITH_INFO + rc == SQL_SUCCESS or rc == SQL_SUCCESS_WITH_INFO or rc == SQL_NEED_DATA end - def error(rc, msg) - raise DBI::DatabaseError.new(msg) unless rc_ok(rc) + def error(rc, msg, handleType=nil, handle=nil) + begin + unless handle.nil? or handleType.nil? + SQLGetDiagRec(handleType, handle, 1, 512).each { |a| msg << "\n\t#{a}" } + end + raise DBI::DatabaseError.new(msg, rc) + end unless rc_ok(rc) end end # module DB2Util @@ -65,10 +72,10 @@ def connect(dbname, user, auth, attr) rc, dbc = SQLAllocHandle(SQL_HANDLE_DBC, @env) - error(rc, "Could not allocate Database Connection") + error(rc, "Could not allocate Database Connection", SQL_HANDLE_ENV, @env) rc = SQLConnect(dbc, dbname, user, auth) - error(rc, "Could not connect to Database") + error(rc, "Could not connect to Database", SQL_HANDLE_DBC, dbc) return Database.new(dbc, attr) end @@ -107,25 +114,26 @@ class Database < DBI::BaseDatabase include Util - include SQL::BasicBind - include SQL::BasicQuote + #include SQL::BasicBind + #include SQL::BasicQuote def disconnect rollback rc = SQLDisconnect(@handle) - error(rc, "Could not disconnect from Database") + error(rc, "Could not disconnect from Database", SQL_HANDLE_DBC, @handle) rc = SQLFreeHandle(SQL_HANDLE_DBC, @handle) - error(rc, "Could not free Database handle") - end + error(rc, "Could not free Database handle", SQL_HANDLE_DBC, @handle) + end +=begin def tables rc, stmt = SQLAllocHandle(SQL_HANDLE_STMT, @handle) - error(rc, "Could not allocate Statement") + error(rc, "Could not allocate Statement", SQL_HANDLE_DBC, @handle) rc = SQLTables(stmt, "", "%", "%", "TABLE, VIEW") - error(rc, "Could not execute SQLTables") + error(rc, "Could not execute SQLTables", SQL_HANDLE_STMT, stmt) st = Statement.new(stmt, nil) res = st.fetch_all @@ -133,7 +141,13 @@ res.collect {|row| row[1].to_s + "." + row[2].to_s} end +=end + def tables + execute("SELECT TABSCHEMA,TABNAME FROM SYSCAT.TABLES").fetch_all.collect { |row| + "#{row[0].strip}.#{row[1].strip}" + } + end def ping begin @@ -145,45 +159,37 @@ return false end end - - def do(stmt, *bindvars) - rc, sth = SQLAllocHandle(SQL_HANDLE_STMT, @handle) - error(rc, "Could not allocate Statement") - - sql = bind(self, stmt, bindvars) - rc = SQLExecDirect(sth, sql) - error(rc, "Could not execute statement") - - rc, rpc = SQLRowCount(sth) - error(rc, "Could not get RPC") - - rc = SQLFreeHandle(SQL_HANDLE_STMT, sth) - error(rc, "Could not free Statement") - - return rpc + + def prepare(sql) + new_statement = Statement.new(@handle, sql) + new_statement.prepare + return new_statement end - def prepare(statement) - rc, stmt = SQLAllocHandle(SQL_HANDLE_STMT, @handle) - error(rc, "Could not allocate Statement") - - Statement.new(stmt, statement) + def []=(attribute, value) + rc = case attribute.downcase + when 'autocommit' + SQLSetConnectAttr(@handle, SQL_ATTR_AUTOCOMMIT, (value ? SQL_AUTOCOMMIT_ON : SQL_AUTOCOMMIT_OFF), SQL_IS_INTEGER) + else -1 + end + error(rc, "Could not set DB2 connection attribute (#{attribute.inspect}=#{value.inspect})", SQL_HANDLE_DBC, @handle) + @attr[attribute] = value + end + + def [](attribute) + @attr[attribute] end - - # TODO - #def []=(attr, value) - #end # TODO: method columns(table) def commit rc = SQLEndTran(SQL_HANDLE_DBC, @handle, SQL_COMMIT) - error(rc, "Could not commit transaction") + error(rc, "Could not commit transaction", SQL_HANDLE_DBC, @handle) end def rollback rc = SQLEndTran(SQL_HANDLE_DBC, @handle, SQL_ROLLBACK) - error(rc, "Could not rollback transaction") + error(rc, "Could not rollback transaction", SQL_HANDLE_DBC, @handle) end end # class Database @@ -193,22 +199,102 @@ include Util include SQL::BasicBind include SQL::BasicQuote - - def initialize(handle, statement) + + attr_reader :handle + + # WARNING: Statement.new first argument is its parent database handle + # and NOT a statement handle (to converge with other DBD drivers API) + def initialize(dbhandle, statement) super(nil) - @handle = handle + @dbhandle = dbhandle @statement = statement + rc, @handle = SQLAllocHandle(SQL_HANDLE_STMT, dbhandle) + error(rc, "Could not allocate Statement", SQL_HANDLE_DBC, dbhandle) @arr = [] - @params = [] @cols = nil - @cols = get_col_info if @statement.nil? + #@cols = get_col_info if @statement.nil? + # + @prepared = false + @params = Hash.new + @boundvars = 0 + puts "#{self}.initialize handle=#{@handle}, dbhandle=#{dbhandle}, statement=#{statement}" if $DEBUG end - + + #Ruby's finalizers are strange: finalizer closure must be defined OUTSIDE self.new() + # so that no reference to object is visible to the finalizer...! + @@__statement_new__ = Statement.method('new') + def self.new(*args) + obj = @@__statement_new__[args[0], args[1]] + puts "new Statement, id=#{obj.id}" if $DEBUG + ObjectSpace.define_finalizer(obj, Statement.finalizer) + return obj + end + def self.finalizer + return proc {|id| + puts "Statement id=#{id} is FINALIZED" if $DEBUG + DB2CLI.free_bound_params(id) + } + end + def prepare + puts "#{self}.prepare hnd=#{@handle} stmt=#{@statement}" if $DEBUG + raise DBI::DatabaseError.new('statement already prepared') if @prepared + rc = SQLPrepare(@handle, @statement) + error(rc, "Could not prepare statement", SQL_HANDLE_STMT, @handle) + if $DEBUG + rc, count = SQLNumParams(@handle) + puts "#{self}.prepare: DB2CLI counted #{count} parameters in statement" + end + parse_params + @prepared = true + end + + def bind_param(param_id, param_value, attribs=nil) + puts "#{self}.bind_param: idx=#{param_id}, param_value.size=#{param_value.to_s.length}, attribs=#{attribs.inspect}" if $DEBUG + raise InterfaceError, "only '?' parameters supported" unless param_id.is_a? Fixnum + direction = SQL_PARAM_INPUT + # TODO: ruby-to-CLI mapping should be done by the DBI layer, not the driver + rc, db2_sql_type, size, decimalDigits = SQLDescribeParam(@handle, param_id) + error(rc, 'SQLDescribeParam failed', SQL_HANDLE_STMT, @handle) + if attribs + case attribs['direction'] + when 'in' then direction = SQL_PARAM_INPUT + when 'out' then direction = SQL_PARAM_OUTPUT + when 'inout' then direction = SQL_PARAM_INPUT_OUTPUT + end + if attribs['sql_type'] + db2_sql_type = DBI_to_DB2_type_mapping[attribs['sql_type']][0] + puts 'db2_sql_type overriden: ' + DBI::Utils::ConstResolver.to_name(DBI::DB2CLI, db2_sql_type).join(',') if $DEBUG + end + end + # do the doo + rc = SQLBindParameter(@handle, param_id, direction, db2_sql_type, param_value) + error(rc, "Could not bind parameter #{param_id.inspect}", SQL_HANDLE_STMT, @handle) + @boundvars += 1 + end + +=begin def bind_param(param, value, attribs) raise InterfaceError, "only ? parameters supported" unless param.is_a? Fixnum @params[param-1] = value end +=end + + def execute + puts "#{self}.execute" if $DEBUG + if @prepared and (@params.size != @boundvars) + errstr = (@params.size < @boundvars)? 'Too many' : 'Not enough' + errstr << " SQL parameters (expected #{@params.size}, got #{@boundvars})" + raise DBI::DatabaseError.new(errstr) + end + + rc = SQLExecute(@handle) + error(rc, "Could not execute statement:\n#{@statement}", SQL_HANDLE_STMT, @handle) + + @cols = get_col_info + backbind_params + end +=begin def execute sql = bind(self, @statement, @params) @@ -220,10 +306,12 @@ #rc = SQLExecute(@handle) #error(rc, "Could not execute statement") end +=end def finish + flush_params rc = SQLFreeHandle(SQL_HANDLE_STMT, @handle) - error(rc, "Could not free Statement") + error(rc, "Could not free Statement", SQL_HANDLE_STMT, @handle) end def fetch @@ -250,18 +338,55 @@ def cancel rc = SQLFreeStmt(@handle, SQL_CLOSE) - error(rc, "Could not close/cancel statment") + error(rc, "Could not close/cancel statement", SQL_HANDLE_STMT, @handle) @cols = nil end def rows rc, rpc = SQLRowCount(@handle) - error(rc, "Could not get RPC") + error(rc, "Could not get RPC", SQL_HANDLE_STMT, @handle) return rpc end - + #------ private + #------ + + # parses statements for parameters + def parse_params + puts "#{self}.parse_params" if $DEBUG + result = "" + @params = [] + #flush_params + #puts "statement tokens: #{tokens(@statement).join(', ')}" if $DEBUG + tokens(@statement).each { |part| + case part + when '?' + @params << part + result << '?' + when '??' + result << '?' + else + result << part + end + } + puts "#{self}.parse_params: params size=#{@params.size}" if $DEBUG + end + + # binds inout/out (result) parameter buffers after query execution into ruby values + def backbind_params + puts "#{self}.backbind_params" if $DEBUG + flush_params + # TODO: some beautiful code that uses @boundvars to return new Ruby values + # from stored procedure execution + end + + # frees buffers allocated for inout/out parameters + def flush_params + puts "#{self}.flush_params" if $DEBUG + DB2CLI.free_bound_params(self.id) # let CLI free up its internal param buffers + @boundvars = 0 + end # TODO: check typenames DB2_to_DBI_type_mapping = { @@ -300,6 +425,42 @@ DB2CLI::SQL_LONGVARGRAPHIC => [DBI::SQL_OTHER, 'LONG VARGRAPHIC'] } + DBI_to_DB2_type_mapping = { + DBI::SQL_DOUBLE => [DB2CLI::SQL_DOUBLE, 'DOUBLE'], + DBI::SQL_FLOAT => [DB2CLI::SQL_FLOAT, 'FLOAT'], + DBI::SQL_REAL => [DB2CLI::SQL_REAL, 'REAL'], + + DBI::SQL_INTEGER => [DB2CLI::SQL_INTEGER, 'INTEGER'], + DBI::SQL_BIGINT => [DB2CLI::SQL_BIGINT, 'BIGINT'], + DBI::SQL_SMALLINT => [DB2CLI::SQL_SMALLINT, 'SMALLINT'], + + DBI::SQL_DECIMAL => [DB2CLI::SQL_DECIMAL, 'DECIMAL'], + DBI::SQL_NUMERIC => [DB2CLI::SQL_NUMERIC, 'NUMERIC'], + + DBI::SQL_DATE => [DB2CLI::SQL_TYPE_DATE, 'DATE'], + DBI::SQL_TIME => [DB2CLI::SQL_TYPE_TIME, 'TIME'], + DBI::SQL_TIMESTAMP => [DB2CLI::SQL_TYPE_TIMESTAMP,'TIMESTAMP'], + + DBI::SQL_CHAR => [DB2CLI::SQL_CHAR, 'CHAR'], + DBI::SQL_VARCHAR => [DB2CLI::SQL_VARCHAR, 'VARCHAR'], + DBI::SQL_LONGVARCHAR => [DB2CLI::SQL_LONGVARCHAR, 'LONG VARCHAR'], + DBI::SQL_CLOB => [DB2CLI::SQL_CLOB, 'CLOB'], + + DBI::SQL_BINARY => [DB2CLI::SQL_BINARY, 'BINARY'], + DBI::SQL_VARBINARY => [DB2CLI::SQL_VARBINARY, 'VARBINARY'], + DBI::SQL_LONGVARBINARY => [DB2CLI::SQL_LONGVARBINARY, 'LONG VARBINARY'], + DBI::SQL_BLOB => [DB2CLI::SQL_BLOB, 'BLOB'], + + # DB2 specific types + 'SQL_BLOB_LOCATOR' => [DB2CLI::SQL_BLOB_LOCATOR, 'BLOB LOCATOR'], + 'SQL_CLOB_LOCATOR' => [DB2CLI::SQL_CLOB_LOCATOR, 'CLOB LOCATOR'], + 'SQL_DBCLOB' => [DB2CLI::SQL_DBCLOB, 'DBCLOB'], + 'SQL_DBCLOB_LOCATOR' => [DB2CLI::SQL_DBCLOB_LOCATOR, 'DBCLOB LOCATOR'], + 'SQL_GRAPHIC' => [DB2CLI::SQL_GRAPHIC, 'GRAPHIC'], + 'SQL_VARGRAPHIC' => [DB2CLI::SQL_VARGRAPHIC, 'VARGRAPHIC'], + 'SQL_LONGVARGRAPHIC' => [DB2CLI::SQL_LONGVARGRAPHIC, 'LONG VARGRAPHIC'] + } + MAX_COL_SIZE = 256 # @@ -307,11 +468,11 @@ # def get_col_info rc, nr_cols = SQLNumResultCols(@handle) - error(rc, "Could not get number of result columns") + error(rc, "Could not get number of result columns", SQL_HANDLE_STMT, @handle) (1..nr_cols).collect do |c| rc, column_name, buflen, data_type, column_size, decimal_digits, nullable = SQLDescribeCol(@handle, c, MAX_COL_SIZE) - error(rc, "Could not describe column") + error(rc, "Could not describe column", @handle, SQL_HANDLE_STMT) sql_type, type_name = DB2_to_DBI_type_mapping[data_type] @@ -329,11 +490,11 @@ def do_fetch(rc) return nil if rc == SQL_NO_DATA_FOUND - error(rc, "Could not fetch row") + error(rc, "Could not fetch row", @handle, SQL_HANDLE_STMT) @cols.each_with_index do |c, i| rc, content = SQLGetData(@handle, i+1, c['db2_type'], c['precision']) - error(rc, "Could not get data") + error(rc, "Could not get data", @handle, SQL_HANDLE_STMT) @arr[i] = case content |