ydbi 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +6 -0
  3. data/ChangeLog +3699 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE +25 -0
  6. data/Rakefile +8 -0
  7. data/TODO +44 -0
  8. data/bench/bench.rb +79 -0
  9. data/bin/dbi +518 -0
  10. data/bin/test_broken_dbi +37 -0
  11. data/build/Rakefile.dbi.rb +60 -0
  12. data/build/rake_task_lib.rb +187 -0
  13. data/doc/DBD_SPEC.rdoc +88 -0
  14. data/doc/DBI_SPEC.rdoc +157 -0
  15. data/doc/homepage/contact.html +62 -0
  16. data/doc/homepage/development.html +124 -0
  17. data/doc/homepage/index.html +83 -0
  18. data/doc/homepage/ruby-dbi.css +91 -0
  19. data/examples/test1.pl +39 -0
  20. data/examples/test1.rb +20 -0
  21. data/examples/xmltest.rb +8 -0
  22. data/lib/dbd/Mysql.rb +137 -0
  23. data/lib/dbd/ODBC.rb +89 -0
  24. data/lib/dbd/Pg.rb +188 -0
  25. data/lib/dbd/SQLite.rb +97 -0
  26. data/lib/dbd/SQLite3.rb +124 -0
  27. data/lib/dbd/mysql/database.rb +405 -0
  28. data/lib/dbd/mysql/driver.rb +125 -0
  29. data/lib/dbd/mysql/statement.rb +188 -0
  30. data/lib/dbd/odbc/database.rb +128 -0
  31. data/lib/dbd/odbc/driver.rb +38 -0
  32. data/lib/dbd/odbc/statement.rb +137 -0
  33. data/lib/dbd/pg/database.rb +516 -0
  34. data/lib/dbd/pg/exec.rb +47 -0
  35. data/lib/dbd/pg/statement.rb +160 -0
  36. data/lib/dbd/pg/tuples.rb +121 -0
  37. data/lib/dbd/pg/type.rb +209 -0
  38. data/lib/dbd/sqlite/database.rb +151 -0
  39. data/lib/dbd/sqlite/statement.rb +125 -0
  40. data/lib/dbd/sqlite3/database.rb +201 -0
  41. data/lib/dbd/sqlite3/statement.rb +78 -0
  42. data/lib/dbi.rb +336 -0
  43. data/lib/dbi/base_classes.rb +12 -0
  44. data/lib/dbi/base_classes/database.rb +135 -0
  45. data/lib/dbi/base_classes/driver.rb +47 -0
  46. data/lib/dbi/base_classes/statement.rb +171 -0
  47. data/lib/dbi/binary.rb +25 -0
  48. data/lib/dbi/columninfo.rb +107 -0
  49. data/lib/dbi/exceptions.rb +65 -0
  50. data/lib/dbi/handles.rb +49 -0
  51. data/lib/dbi/handles/database.rb +241 -0
  52. data/lib/dbi/handles/driver.rb +60 -0
  53. data/lib/dbi/handles/statement.rb +408 -0
  54. data/lib/dbi/row.rb +269 -0
  55. data/lib/dbi/sql.rb +22 -0
  56. data/lib/dbi/sql/preparedstatement.rb +115 -0
  57. data/lib/dbi/sql_type_constants.rb +75 -0
  58. data/lib/dbi/trace.rb +91 -0
  59. data/lib/dbi/types.rb +218 -0
  60. data/lib/dbi/typeutil.rb +109 -0
  61. data/lib/dbi/utils.rb +60 -0
  62. data/lib/dbi/utils/date.rb +59 -0
  63. data/lib/dbi/utils/tableformatter.rb +112 -0
  64. data/lib/dbi/utils/time.rb +52 -0
  65. data/lib/dbi/utils/timestamp.rb +96 -0
  66. data/lib/dbi/utils/xmlformatter.rb +73 -0
  67. data/lib/dbi/version.rb +3 -0
  68. data/prototypes/types2.rb +237 -0
  69. data/readme.md +274 -0
  70. data/setup.rb +1585 -0
  71. data/test/DBD_TESTS +50 -0
  72. data/test/TESTING +16 -0
  73. data/test/dbd/general/test_database.rb +206 -0
  74. data/test/dbd/general/test_statement.rb +326 -0
  75. data/test/dbd/general/test_types.rb +296 -0
  76. data/test/dbd/mysql/base.rb +26 -0
  77. data/test/dbd/mysql/down.sql +19 -0
  78. data/test/dbd/mysql/test_blob.rb +18 -0
  79. data/test/dbd/mysql/test_new_methods.rb +7 -0
  80. data/test/dbd/mysql/test_patches.rb +111 -0
  81. data/test/dbd/mysql/up.sql +28 -0
  82. data/test/dbd/odbc/base.rb +30 -0
  83. data/test/dbd/odbc/down.sql +19 -0
  84. data/test/dbd/odbc/test_new_methods.rb +12 -0
  85. data/test/dbd/odbc/test_ping.rb +10 -0
  86. data/test/dbd/odbc/test_statement.rb +44 -0
  87. data/test/dbd/odbc/test_transactions.rb +58 -0
  88. data/test/dbd/odbc/up.sql +33 -0
  89. data/test/dbd/postgresql/base.rb +31 -0
  90. data/test/dbd/postgresql/down.sql +31 -0
  91. data/test/dbd/postgresql/test_arrays.rb +179 -0
  92. data/test/dbd/postgresql/test_async.rb +121 -0
  93. data/test/dbd/postgresql/test_blob.rb +36 -0
  94. data/test/dbd/postgresql/test_bytea.rb +87 -0
  95. data/test/dbd/postgresql/test_ping.rb +10 -0
  96. data/test/dbd/postgresql/test_timestamp.rb +77 -0
  97. data/test/dbd/postgresql/test_transactions.rb +58 -0
  98. data/test/dbd/postgresql/testdbipg.rb +307 -0
  99. data/test/dbd/postgresql/up.sql +60 -0
  100. data/test/dbd/sqlite/base.rb +32 -0
  101. data/test/dbd/sqlite/test_database.rb +30 -0
  102. data/test/dbd/sqlite/test_driver.rb +68 -0
  103. data/test/dbd/sqlite/test_statement.rb +112 -0
  104. data/test/dbd/sqlite/up.sql +25 -0
  105. data/test/dbd/sqlite3/base.rb +32 -0
  106. data/test/dbd/sqlite3/test_database.rb +77 -0
  107. data/test/dbd/sqlite3/test_driver.rb +67 -0
  108. data/test/dbd/sqlite3/test_statement.rb +88 -0
  109. data/test/dbd/sqlite3/up.sql +33 -0
  110. data/test/dbi/tc_columninfo.rb +94 -0
  111. data/test/dbi/tc_date.rb +88 -0
  112. data/test/dbi/tc_dbi.rb +184 -0
  113. data/test/dbi/tc_row.rb +256 -0
  114. data/test/dbi/tc_sqlbind.rb +168 -0
  115. data/test/dbi/tc_statementhandle.rb +29 -0
  116. data/test/dbi/tc_time.rb +77 -0
  117. data/test/dbi/tc_timestamp.rb +142 -0
  118. data/test/dbi/tc_types.rb +268 -0
  119. data/test/ts_dbd.rb +131 -0
  120. data/test/ts_dbi.rb +16 -0
  121. data/ydbi.gemspec +24 -0
  122. metadata +224 -0
@@ -0,0 +1,47 @@
1
+ module DBI
2
+
3
+ # Implements the basic functionality that constitutes a Driver
4
+ #
5
+ # Drivers do not have a direct interface exposed to the user; these methods
6
+ # are mostly for DBD authors.
7
+ #
8
+ # As with DBI::BaseDatabase, "DBD Required" and "DBD Optional" will be used
9
+ # to explain the same requirements.
10
+ #
11
+ class BaseDriver < Base
12
+ def initialize(dbi_version)
13
+ major, minor = dbi_version.split(".").collect { |x| x.to_i }
14
+ dbi_major, dbi_minor = DBI::VERSION.split(".").collect { |x| x.to_i }
15
+ unless major == dbi_major and minor == dbi_minor
16
+ raise InterfaceError, "Wrong DBD API version used"
17
+ end
18
+ end
19
+
20
+ # Connect to the database. DBD Required.
21
+ def connect(dbname, user, auth, attr)
22
+ raise NotImplementedError
23
+ end
24
+
25
+ # Default u/p information in an array.
26
+ def default_user
27
+ ['', '']
28
+ end
29
+
30
+ # Default attributes to set on the DatabaseHandle.
31
+ def default_attributes
32
+ {}
33
+ end
34
+
35
+ # Return the data sources available to this driver. Returns an empty
36
+ # array per default.
37
+ def data_sources
38
+ []
39
+ end
40
+
41
+ # Disconnect all DatabaseHandles. DBD Required.
42
+ def disconnect_all
43
+ raise NotImplementedError
44
+ end
45
+
46
+ end # class BaseDriver
47
+ end
@@ -0,0 +1,171 @@
1
+ module DBI
2
+ #
3
+ # StatementHandles are used to encapsulate the process of managing a
4
+ # statement (DDL or DML) and its parameters, sending it to the database,
5
+ # and gathering any results from the execution of that statement.
6
+ #
7
+ # As with the other `Base` classes, the terms "DBD Required" and "DBD
8
+ # Optional" are defined in DBI::BaseDatabase.
9
+ #
10
+ class BaseStatement < Base
11
+
12
+ attr_accessor :raise_error
13
+
14
+ def initialize(attr=nil)
15
+ @attr = attr || {}
16
+ end
17
+
18
+ #
19
+ # Bind a parameter to the statement. DBD Required.
20
+ #
21
+ # The parameter number is numeric and indexes starting at 1. This
22
+ # corresponds to the question marks (?) in the statement from the
23
+ # left-most part of the statement moving forward.
24
+ #
25
+ # The value may be any ruby type. How these are handled is
26
+ # DBD-dependent, but the vast majority of DBDs will convert these to
27
+ # string inside the query.
28
+ #
29
+ def bind_param(param, value, attribs)
30
+ raise NotImplementedError
31
+ end
32
+
33
+ #
34
+ # Execute the statement with the known binds. DBD Required.
35
+ #
36
+ def execute
37
+ raise NotImplementedError
38
+ end
39
+
40
+ #
41
+ # Close the statement and any result cursors. DBD Required.
42
+ #
43
+ # Note:: Most implementations will fail miserably if you forget to
44
+ # finish your statement handles.
45
+ def finish
46
+ raise NotImplementedError
47
+ end
48
+
49
+ #
50
+ # Fetch the next row in the result set. DBD Required.
51
+ #
52
+ # DBI::Row is responsible for formatting the data the DBD provides it.
53
+ #
54
+ def fetch
55
+ raise NotImplementedError
56
+ end
57
+
58
+ ##
59
+ # returns result-set column information as array
60
+ # of hashs, where each hash represents one column. See
61
+ # BaseDatabase#columns. DBD Required.
62
+ #
63
+ def column_info
64
+ raise NotImplementedError
65
+ end
66
+
67
+ #============================================
68
+ # OPTIONAL
69
+ #============================================
70
+
71
+ #
72
+ # Take a list of bind variables and bind them successively using bind_param.
73
+ #
74
+ def bind_params(*bindvars)
75
+ bindvars.each_with_index {|val,i| bind_param(i+1, val, nil) }
76
+ self
77
+ end
78
+
79
+ #
80
+ # Cancel any result cursors. DBD Optional, but intentionally does not
81
+ # raise any exception as it's used internally to maintain consistency.
82
+ #
83
+ def cancel
84
+ end
85
+
86
+ #
87
+ # fetch_scroll is provided with a direction and offset and works
88
+ # similar to how seek() is used on files.
89
+ #
90
+ # The constants available for direction are as follows:
91
+ #
92
+ # * SQL_FETCH_NEXT: fetch the next result.
93
+ # * SQL_FETCH_LAST: fetch the last result, period.
94
+ # * SQL_FETCH_RELATIVE: fetch the result at the offset.
95
+ #
96
+ # Other constants can be used, but if this method is not supplied by
97
+ # the driver, they will result in a raise of DBI::NotSupportedError.
98
+ #
99
+
100
+ def fetch_scroll(direction, offset)
101
+ case direction
102
+ when SQL_FETCH_NEXT
103
+ return fetch
104
+ when SQL_FETCH_LAST
105
+ last_row = nil
106
+ while (row=fetch) != nil
107
+ last_row = row
108
+ end
109
+ return last_row
110
+ when SQL_FETCH_RELATIVE
111
+ raise NotSupportedError if offset <= 0
112
+ row = nil
113
+ offset.times { row = fetch; break if row.nil? }
114
+ return row
115
+ else
116
+ raise NotSupportedError
117
+ end
118
+ end
119
+
120
+ #
121
+ # fetch x rows. The result is Array of DBI::Row.
122
+ #
123
+ def fetch_many(cnt)
124
+ rows = []
125
+ cnt.times do
126
+ row = fetch
127
+ break if row.nil?
128
+ rows << row.dup
129
+ end
130
+
131
+ if rows.empty?
132
+ nil
133
+ else
134
+ rows
135
+ end
136
+ end
137
+
138
+ #
139
+ # Fetch all available rows. Result is Array of DBI::Row.
140
+ #
141
+ def fetch_all
142
+ rows = []
143
+ loop do
144
+ row = fetch
145
+ break if row.nil?
146
+ rows << row.dup
147
+ end
148
+
149
+ if rows.empty?
150
+ nil
151
+ else
152
+ rows
153
+ end
154
+ end
155
+
156
+ #
157
+ # Get statement attributes.
158
+ #
159
+ def [](attr)
160
+ @attr ||= { }
161
+ @attr[attr]
162
+ end
163
+
164
+ #
165
+ # Set statement attributes. DBD Optional.
166
+ #
167
+ def []=(attr, value)
168
+ raise NotSupportedError
169
+ end
170
+ end # class BaseStatement
171
+ end
@@ -0,0 +1,25 @@
1
+ module DBI
2
+ #
3
+ # Encapsulates the concept of a CLOB/BLOB, which can then be passed as a
4
+ # bind via BaseStatement#bind_param.
5
+ #
6
+ # This is similar to a DBI::Type class and will eventually find its way
7
+ # there.
8
+ #
9
+ # See #new for usage.
10
+ class Binary
11
+ attr_accessor :data
12
+
13
+ # Construct a new DBI::Binary object with the data supplied as string.
14
+ # This object can then be used in bound variables to represent a CLOB
15
+ # or BLOB type.
16
+ def initialize(data)
17
+ @data = data
18
+ end
19
+
20
+ # Return the string representation of the DBI::Binary object.
21
+ def to_s
22
+ @data
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,107 @@
1
+ require 'delegate'
2
+
3
+ begin
4
+ require 'rubygems'
5
+ gem 'deprecated', "= 2.0.1"
6
+ rescue LoadError => e
7
+ end
8
+
9
+ require 'deprecated'
10
+
11
+ module DBI
12
+ # This represents metadata for columns within a given table, such as the
13
+ # data type, whether or not the the column is a primary key, etc.
14
+ #
15
+ # ColumnInfo is a delegate of Hash, but represents its keys indifferently,
16
+ # coercing all strings to symbols. It also has ostruct-like features, f.e.:
17
+ #
18
+ # h = ColumnInfo.new({ "foo" => "bar" })
19
+ # h[:foo] => "bar"
20
+ # h["foo"] => "bar"
21
+ # h.foo => "bar"
22
+ #
23
+ # All of these forms have assignment forms as well.
24
+ #
25
+ class ColumnInfo < DelegateClass(Hash)
26
+
27
+ # Create a new ColumnInfo object.
28
+ #
29
+ # If no Hash is provided, one will be created for you. The hash will be
30
+ # shallow cloned for storage inside the object, and an attempt will be
31
+ # made to convert all string keys to symbols.
32
+ #
33
+ # In the event that both string and symbol keys are provided in the
34
+ # initial hash, we cannot safely route around collisions and therefore
35
+ # a TypeError is raised.
36
+ #
37
+ def initialize(hash=nil)
38
+ @hash = hash.dup rescue nil
39
+ @hash ||= Hash.new
40
+
41
+ # coerce all strings to symbols
42
+ @hash.keys.each do |x|
43
+ if x.kind_of? String
44
+ sym = x.to_sym
45
+ if @hash.has_key? sym
46
+ raise ::TypeError,
47
+ "#{self.class.name} may construct from a hash keyed with strings or symbols, but not both"
48
+ end
49
+ @hash[sym] = @hash[x]
50
+ @hash.delete(x)
51
+ end
52
+ end
53
+
54
+ super(@hash)
55
+ end
56
+
57
+ def [](key)
58
+ @hash[key.to_sym]
59
+ end
60
+
61
+ def []=(key, value)
62
+ @hash[key.to_sym] = value
63
+ end
64
+
65
+ def default() # :nodoc; XXX hack to get around Hash#default
66
+ method_missing(:default)
67
+ end
68
+
69
+ def method_missing(sym, value=nil)
70
+ if sym.to_s =~ /=$/
71
+ sym = sym.to_s.sub(/=$/, '').to_sym
72
+ @hash[sym] = value
73
+ elsif sym.to_s =~ /\?$/
74
+ sym = sym.to_s.sub(/\?$/, '').to_sym
75
+ @hash[sym]
76
+ else
77
+ @hash[sym]
78
+ end
79
+ end
80
+
81
+ # Aliases - XXX soon to be deprecated
82
+ def self.deprecated_alias(target, source) # :nodoc:
83
+ define_method(target) { |*args| method_missing(source, *args) }
84
+ deprecate target
85
+ end
86
+
87
+ deprecated_alias :is_nullable?, :nullable
88
+ deprecated_alias :can_be_null?, :nullable
89
+
90
+ deprecated_alias :is_indexed?, :indexed
91
+
92
+ deprecated_alias :is_primary?, :primary
93
+
94
+ deprecated_alias :is_unique, :unique
95
+
96
+ deprecated_alias :size, :precision
97
+ deprecated_alias :size=, :precision=
98
+ deprecated_alias :length, :precision
99
+ deprecated_alias :length=, :precision=
100
+
101
+ deprecated_alias :decimal_digits, :scale
102
+ deprecated_alias :decimal_digits=, :scale=
103
+
104
+ deprecated_alias :default_value, :default
105
+ deprecated_alias :default_value=, :default=
106
+ end
107
+ end
@@ -0,0 +1,65 @@
1
+ module DBI
2
+ # Exceptions (borrowed by Python API 2.0)
3
+
4
+ # Base class of all other error exceptions. Use this to catch all DBI
5
+ # errors.
6
+ class Error < RuntimeError
7
+ end
8
+
9
+ # For important warnings like data truncation, etc.
10
+ class Warning < RuntimeError
11
+ end
12
+
13
+ # Exception for errors related to the DBI interface rather than the
14
+ # database itself.
15
+ class InterfaceError < Error
16
+ end
17
+
18
+ # Exception raised if the DBD driver has not specified a mandatory method.
19
+ class NotImplementedError < InterfaceError
20
+ end
21
+
22
+ # Exception for errors related to the database.
23
+ class DatabaseError < Error
24
+ attr_reader :err, :errstr, :state
25
+
26
+ def initialize(errstr="", err=nil, state=nil)
27
+ super(errstr)
28
+ @err, @errstr, @state = err, errstr, state
29
+ end
30
+ end
31
+
32
+ # Exception for errors due to problems with the processed
33
+ # data such as division by zero, numeric value out of range, etc.
34
+ class DataError < DatabaseError
35
+ end
36
+
37
+ # Exception for errors related to the database's operation which are not
38
+ # necessarily under the control of the programmer. This includes such
39
+ # things as unexpected disconnect, datasource name not found, transaction
40
+ # could not be processed, a memory allocation error occured during
41
+ # processing, etc.
42
+ class OperationalError < DatabaseError
43
+ end
44
+
45
+ # Exception raised when the relational integrity of the database
46
+ # is affected, e.g. a foreign key check fails.
47
+ class IntegrityError < DatabaseError
48
+ end
49
+
50
+ # Exception raised when the database encounters an internal error,
51
+ # e.g. the cursor is not valid anymore, the transaction is out of sync.
52
+ class InternalError < DatabaseError
53
+ end
54
+
55
+ # Exception raised for programming errors, e.g. table not found
56
+ # or already exists, syntax error in SQL statement, wrong number
57
+ # of parameters specified, etc.
58
+ class ProgrammingError < DatabaseError
59
+ end
60
+
61
+ # Exception raised if e.g. commit() is called for a database which do not
62
+ # support transactions.
63
+ class NotSupportedError < DatabaseError
64
+ end
65
+ end
@@ -0,0 +1,49 @@
1
+ #
2
+ # Dispatch classes (Handle, DriverHandle, DatabaseHandle and StatementHandle)
3
+ #
4
+
5
+ module DBI
6
+ #
7
+ # Base class for all handles.
8
+ #
9
+ class Handle
10
+ attr_reader :trace_mode, :trace_output
11
+ attr_reader :handle
12
+ attr :convert_types, true
13
+
14
+ def initialize(handle, convert_types=true)
15
+ @handle = handle
16
+ @trace_mode = @trace_output = nil
17
+ @convert_types = convert_types
18
+ end
19
+
20
+ # Please seee DBI.trace.
21
+ def trace(mode=nil, output=nil)
22
+ # FIXME trace
23
+ raise InterfaceError, "the trace module has been removed until it actually works."
24
+ @trace_mode = mode || @trace_mode || DBI::DEFAULT_TRACE_MODE
25
+ @trace_output = output || @trace_output || DBI::DEFAULT_TRACE_OUTPUT
26
+ end
27
+
28
+ #
29
+ # Leverage a driver-specific method. The method name will have "__"
30
+ # prepended to them before calling, and the DBD must define them as
31
+ # such for them to work.
32
+ #
33
+ def func(function, *values)
34
+ if @handle.respond_to?("__" + function.to_s) then
35
+ @handle.send("__" + function.to_s, *values)
36
+ else
37
+ raise InterfaceError, "Driver specific function <#{function}> not available."
38
+ end
39
+ rescue ArgumentError
40
+ raise InterfaceError, "Wrong # of arguments for driver specific function"
41
+ end
42
+
43
+ # error functions?
44
+ end
45
+ end
46
+
47
+ require 'dbi/handles/driver'
48
+ require 'dbi/handles/database'
49
+ require 'dbi/handles/statement'