ydbi 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
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'