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
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ # A sample Gemfile
2
+ source "https://rubygems.org"
3
+
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,25 @@
1
+ (C) 2008 Erik Hollensbe <erik@hollensbe.org>. All rights reserved.
2
+
3
+ Please see "README" for earlier copyrights.
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions
7
+ are met:
8
+ 1. Redistributions of source code must retain the above copyright
9
+ notice, this list of conditions and the following disclaimer.
10
+ 2. Redistributions in binary form must reproduce the above copyright
11
+ notice, this list of conditions and the following disclaimer in the
12
+ documentation and/or other materials provided with the distribution.
13
+ 3. The name of the author may not be used to endorse or promote products
14
+ derived from this software without specific prior written permission.
15
+
16
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
17
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
18
+ AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
19
+ THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22
+ OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24
+ OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25
+ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,8 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ # dependencies are now declared in ydim.gemspec
4
+ desc 'Offer a gem task like hoe'
5
+ task :gem => :build do
6
+ Rake::Task[:build].invoke
7
+ end
8
+
data/TODO ADDED
@@ -0,0 +1,44 @@
1
+ 0.4.0:
2
+ x Work
3
+ x Postgres quoting toggles
4
+ x Postgres binding toggles
5
+ x Test for #20489
6
+ * Release checklist:
7
+ x Update ChangeLog
8
+ x rake
9
+ x remove all related gems, install all DBI/DBD gems (check prereqs)
10
+ x write a few test scripts to make sure drivers are loading
11
+ x Update homepage (irc channel, git, other changes)
12
+ * tag as 0.4.0
13
+ * upload rdoc
14
+ * upload packages
15
+ * release announcement (rf, ruby-talk, dbi lists, other places?)
16
+ * rebase master from development
17
+ * BEER
18
+ 0.6.0:
19
+ * Cleanup:
20
+ * Arrays:
21
+ * Find some way to get the extents of an array type
22
+ * checked pg_type, pg_attribute and pg_class, can't find anything.
23
+ * I don't think this is possible, but let's slate it for 0.6.0 anyways.
24
+ * Tracing
25
+ * WTH do we want to do with this
26
+ * Wow, this module has *serious issues*. Crashes DBI without warning. Redo this completely.
27
+ * 0.6.0
28
+ * Re-institute drivers
29
+ * Proxy
30
+ * Slated for 0.6.0
31
+ * Finish type management system
32
+ * Unify ColumnInfo
33
+ * Should we enforce ColumnInfo requirements at the DBI level?
34
+ * At least test the result of statement colinfo uniformly
35
+ * 0.6.0
36
+ * Cleanup core
37
+ * Require code is a mess
38
+ * Just remove the case-sensitivity from the DBDs in general
39
+ * 0.6.0
40
+ * Find a good clean way to enumerate drivers in separate gems
41
+ * Some registration-on-require would be cleaner and safer
42
+ * 0.6.0
43
+ * Scripts
44
+ * bin/dbd_proxy seems to have never worked; slate it for 0.6.0
@@ -0,0 +1,79 @@
1
+ require 'rubygems'
2
+ $:.unshift File.dirname(__FILE__) + '/../lib'
3
+ require 'dbi'
4
+
5
+ class DbiBenchmark
6
+ attr_reader :db
7
+
8
+ def initialize db, quiet=false
9
+ @db = db
10
+ @quiet = quiet
11
+ end
12
+
13
+ def puts(*args)
14
+ super unless @quiet
15
+ end
16
+
17
+ def run
18
+ times = {}
19
+ %w[create_test_table selecting_floats selecting_datetimes].each do |name|
20
+ t = Time.now
21
+ puts "* #{name.tr('_', ' ').capitalize}"
22
+ send name
23
+ took = Time.now - t
24
+ puts " (took #{took} seconds)"
25
+ puts
26
+ times[name] = took
27
+ end
28
+ times
29
+ ensure
30
+ db.do 'drop table data'
31
+ end
32
+
33
+ def create_test_table
34
+ db.do <<-end
35
+ create table data (
36
+ date timestamp,
37
+ value float
38
+ )
39
+ end
40
+ db.do 'begin'
41
+ today = Date.today
42
+ 5_000.times do
43
+ db.do "insert into data values ('#{today + rand(100) - 50}', #{10 + rand * 30})"
44
+ end
45
+ db.do 'commit'
46
+ end
47
+
48
+ def selecting_floats
49
+ strs = db.select_all('select value from data').map { |v| v.to_s }
50
+ puts *strs[0, 5]
51
+ puts '...'
52
+ end
53
+
54
+ def selecting_datetimes
55
+ strs = db.select_all('select date from data').map { |v| v.to_s }
56
+ puts *strs[0, 5]
57
+ puts '...'
58
+ end
59
+ end
60
+
61
+ def bench
62
+ dbiurls = [
63
+ 'DBI:Mysql:dbitest:localhost',
64
+ 'DBI:ODBC:MYDBITEST',
65
+ 'DBI:Pg:dbitest:localhost',
66
+ 'DBI:ODBC:PGDBITEST',
67
+ ]
68
+ order = %w[create_test_table selecting_floats selecting_datetimes]
69
+ dbiurls.map do |url|
70
+ # assume all dbs have the same credentials
71
+ DBI.connect(url, *ARGV) do |db|
72
+ [url.first.sub('DBI:', ''), *DbiBenchmark.new(db, true).run.values_at(*order)]
73
+ end
74
+ end
75
+ end
76
+
77
+ puts 'Running benchmark:'
78
+ DBI::Utils::TableFormatter.ascii(%w[db insert float datetime], bench, nil, nil, nil, nil, 30)
79
+
data/bin/dbi ADDED
@@ -0,0 +1,518 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Copyright (c) 2001, 2002 Michael Neumann <neumann@s-direktnet.de>
4
+ #
5
+ # All rights reserved.
6
+ #
7
+ # Redistribution and use in source and binary forms, with or without
8
+ # modification, are permitted provided that the following conditions
9
+ # are met:
10
+ # 1. Redistributions of source code must retain the above copyright
11
+ # notice, this list of conditions and the following disclaimer.
12
+ # 2. Redistributions in binary form must reproduce the above copyright
13
+ # notice, this list of conditions and the following disclaimer in the
14
+ # documentation and/or other materials provided with the distribution.
15
+ # 3. The name of the author may not be used to endorse or promote products
16
+ # derived from this software without specific prior written permission.
17
+ #
18
+ # THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
19
+ # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
20
+ # AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21
+ # THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22
+ # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23
+ # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
24
+ # OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25
+ # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26
+ # OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
27
+ # ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
+ #
29
+ # $Id: sqlsh.rb,v 1.2 2006/01/24 04:20:01 francis Exp $
30
+ #
31
+
32
+ begin
33
+ require 'rubygems'
34
+ gem 'dbi'
35
+ rescue LoadError => e
36
+ end
37
+
38
+ require "dbi"
39
+
40
+ begin
41
+ require "readline"
42
+ $use_readline = true
43
+ rescue LoadError
44
+ $use_readline = false
45
+ end
46
+
47
+ require "irb"
48
+ require "irb/completion"
49
+
50
+ $paging = true
51
+ $irb_completion = Readline.completion_proc
52
+
53
+ require "getoptlong"
54
+
55
+ class ReadlineControl
56
+
57
+ attr_accessor :keywords
58
+
59
+ def initialize
60
+ @keywords = []
61
+ set_prompt
62
+ initCompletion
63
+ end
64
+
65
+ def initCompletion
66
+ if $use_readline
67
+ Readline.completion_proc = proc {|str| complete(str) }
68
+ end
69
+ end
70
+
71
+ def complete(str)
72
+ @keywords.grep(/^#{Regexp.escape(str)}/i)
73
+ end
74
+
75
+ def set_prompt(prompt="> ")
76
+ @prompt = prompt
77
+ end
78
+
79
+ def readline
80
+ if $use_readline
81
+ Readline.readline(@prompt, true)
82
+ else
83
+ print @prompt
84
+ $stdin.readline
85
+ end
86
+ end
87
+
88
+ end
89
+
90
+ class Command
91
+
92
+ def tokens(sql)
93
+ DBI::SQL::PreparedStatement.tokens(sql)
94
+ end
95
+
96
+ def readCommand
97
+ line = ""
98
+
99
+ $rd.set_prompt(PROMPT)
100
+ begin
101
+ if $input.nil?
102
+ # no source file to read from
103
+ l = $rd.readline
104
+ else
105
+ # source file has still data
106
+ l = $input.gets
107
+ if l.nil?
108
+ $input = nil
109
+ next
110
+ end
111
+ end
112
+
113
+ next if l.strip.empty?
114
+ l = l.chomp + "\n"
115
+ line << l
116
+
117
+ puts $file + INPUT + l unless $input.nil?
118
+ $rd.set_prompt(PROMPT_CONT)
119
+ end until complete?(line)
120
+
121
+ return line.strip
122
+ end
123
+
124
+ private
125
+
126
+ def complete?(line)
127
+ line =~ /^\s*\\/ or (tokens(line).last || "") =~ /;\s*$/
128
+ end
129
+ end
130
+
131
+ class Actions
132
+ ACTIONS = [
133
+ [ /^\\q(uit)?\s*$/i, :quit ],
134
+ [ /^\\h(elp)?\s*$/i, :help ],
135
+ [ /^\\t(ables)?/i, :tables ],
136
+ [ /^\\dt/i, :describeTable ],
137
+ [ /^\\s(elect)?/i, :select ],
138
+
139
+ [ /^\\rb/i, :ruby ],
140
+ [ /^\\irb/i, :irb ],
141
+
142
+ [ /^\\c(ommit)?\s*$/i, :commit ],
143
+ [ /^\\r(ollback)?\s*$/i, :rollback ],
144
+ [ /^\\a(utocommit)?(\s+(on|off)?)?\s*$/i, :autocommit ],
145
+ [ /^\\i(nput)?/i, :input ],
146
+ [ /^\\o(utput)?/i, :output ],
147
+ [ /^\\pl/i, :pageLength ],
148
+ [ /^\\p/i, :togglePaging ],
149
+
150
+ [ //, :unknownCommand ]
151
+ ]
152
+
153
+ def dispatchCommand(line)
154
+ ACTIONS.each do |regexp, action|
155
+ if line =~ regexp then
156
+ send(action, $~)
157
+ return
158
+ end
159
+ end
160
+ end
161
+
162
+ def quit(match)
163
+ puts
164
+ puts "BYE"
165
+ puts
166
+
167
+ begin
168
+ Conn.disconnect
169
+ rescue DBI::Error => err
170
+ puts
171
+ puts err.message
172
+ p err.backtrace if $DEBUG
173
+ puts
174
+ end
175
+
176
+ exit
177
+ end
178
+
179
+ def help(match)
180
+ head = %w(Function Description)
181
+ rows = [
182
+ ["\\h[elp]", "Display this help screen"],
183
+ ["", ""],
184
+
185
+ ["\\t[ables]", "Display all available tables"],
186
+ ["\\dt table", "Describe columns of 'table'"],
187
+ ["\\s[elect] table", "short for SELECT * FROM 'table'"],
188
+
189
+ ["", ""],
190
+ ["\\c[ommit]", "Commits the current transaction"],
191
+ ["\\r[ollback]", "Rolls back the current transaction"],
192
+ ["\\a[utocommit]", "Show current autocommit mode"],
193
+ ["\\a[utocommit] on|off", "Switch autocommit mode on/off"],
194
+ ["", ""],
195
+
196
+ ["\\i[nput] filename", "Read and execute lines from 'filename'"],
197
+ ["\\o[utput]", "Disable output"],
198
+ ["\\o[utput] filename", "Store SQL statments the user inputs into 'filename'"],
199
+ ["", ""],
200
+
201
+ ["\\pl n", "Set page length to 'n'"],
202
+ ["\\p", "Toggle paging"],
203
+ ["", ""],
204
+ ["\\rb ...", "Execute the rest of the line as Ruby sourcecode"],
205
+ ["\\irb", "Execute irb within this context"],
206
+
207
+ ["", ""],
208
+
209
+ ["\\q[uit]", "Quit this program"]
210
+ ]
211
+
212
+ puts
213
+ puts "Help: "
214
+ output_table(head, rows)
215
+ puts
216
+ end
217
+
218
+ def tables(match)
219
+ head = ["Table name"]
220
+ rows = Conn.tables.collect {|name| [name]}
221
+
222
+ puts
223
+ puts "Tables: "
224
+ output_table(head, rows)
225
+ puts
226
+ end
227
+
228
+ def describeTable(match)
229
+ table = match.post_match.strip
230
+
231
+ head = %w(name type_name precision scale default nullable indexed primary unique)
232
+
233
+ rows = Conn.columns(table).collect {|col| head.collect{|a| col[a]} }
234
+
235
+ puts
236
+ puts "Table '#{table}': "
237
+ output_table(head, rows)
238
+ puts
239
+ end
240
+
241
+ def select(match)
242
+ executeSQL("SELECT * FROM #{match.post_match};")
243
+ end
244
+
245
+ def commit(match)
246
+ Conn.commit
247
+ puts
248
+ puts "COMMIT"
249
+ puts
250
+ end
251
+
252
+ def rollback(match)
253
+ Conn.rollback
254
+ puts
255
+ puts "ROLLBACK"
256
+ puts
257
+ end
258
+
259
+ def autocommit(match)
260
+ mode = match[3]
261
+ if mode =~ /on/i
262
+ Conn['AutoCommit'] = true
263
+ puts
264
+ puts "AUTOCOMMIT IS NOW ON"
265
+ puts
266
+ elsif mode =~ /off/i
267
+ Conn['AutoCommit'] = false
268
+ puts
269
+ puts "AUTOCOMMIT IS NOW OFF"
270
+ puts
271
+ else
272
+ puts
273
+ if Conn['AutoCommit'] == true
274
+ puts "AUTOCOMMIT is currently switched ON"
275
+ elsif Conn['AutoCommit'] == false
276
+ puts "AUTOCOMMIT is currently switched OFF"
277
+ else
278
+ puts "AUTOCOMMIT is in unknown state"
279
+ end
280
+ puts
281
+ end
282
+ end
283
+
284
+ def input(match)
285
+ puts
286
+ $file = match.post_match.strip
287
+
288
+ begin
289
+ $input = File.open($file)
290
+ puts "EXECUTE file #{$file}"
291
+ puts
292
+ rescue
293
+ puts "Couldn't read from file #{$file}"
294
+ puts
295
+ end
296
+ end
297
+
298
+ def output(match)
299
+ puts
300
+ file = match.post_match.strip
301
+
302
+ if file.empty?
303
+ $output.close if $output
304
+ $output = nil
305
+ puts "Disabled OUTPUT"
306
+ puts
307
+ else
308
+ begin
309
+ $output = File.new(file, "w+")
310
+ puts "Set OUTPUT to file #{file}"
311
+ puts
312
+ rescue
313
+ puts "Couldn't set OUTPUT to file #{file}"
314
+ puts
315
+ end
316
+ end
317
+ end
318
+
319
+ def togglePaging(match)
320
+ $paging = !$paging
321
+
322
+ puts "Paging is now " + ($paging ? "on" : "off") + "."
323
+ end
324
+
325
+ def pageLength(match)
326
+ puts
327
+ $page_len = match.post_match.strip.to_i
328
+ $page_len = DEFAULT_PAGE_LENGTH if $page_len <= 0
329
+
330
+ puts "New page length is #{$page_len}."
331
+ puts
332
+ end
333
+
334
+ def irb(match)
335
+ Readline.completion_proc = $irb_completion
336
+ puts
337
+ puts "================================== IRB ==============================="
338
+ begin
339
+ IRB.start
340
+ rescue SystemExit
341
+ end
342
+ puts "======================================================================"
343
+ $rd.initCompletion
344
+ end
345
+
346
+ def ruby(match)
347
+ puts
348
+ eval match.post_match
349
+ puts
350
+ end
351
+
352
+ def unknownCommand(match)
353
+ puts
354
+ puts "Unknown command!"
355
+ puts
356
+ end
357
+
358
+ end
359
+
360
+ def output_table(header, rows)
361
+ DBI::Utils::TableFormatter.ascii(header, rows, nil, nil, nil, nil, $page_len) do
362
+ if $paging
363
+ print "[enter to continue, a to abort]"
364
+ break if $stdin.readline.chomp.downcase == "a"
365
+ end
366
+ end
367
+ end
368
+
369
+ def executeSQL(sql)
370
+ sql = $` if sql =~ /;\s*$/
371
+
372
+ start = ::Time.now
373
+ stmt = Conn.execute(sql)
374
+
375
+ head = stmt.column_names
376
+
377
+ # DDL, DCL
378
+ if head.empty?
379
+ puts
380
+ nr = stmt.rows
381
+ if nr == 0
382
+ puts " No rows affected"
383
+ elsif nr == 1
384
+ puts " 1 row affected"
385
+ else
386
+ puts " #{nr} rows affected"
387
+ end
388
+ puts
389
+ else
390
+ rows = stmt.fetch_all
391
+ tm = ::Time.now - start
392
+
393
+ puts
394
+ output_table(head, rows || [])
395
+ print " "
396
+ if rows.nil?
397
+ print "No rows in set"
398
+ elsif rows.size == 1
399
+ print "1 row in set"
400
+ else
401
+ print "#{rows.size} rows in set"
402
+ end
403
+
404
+ puts " (#{(tm.to_f*1000).to_i / 1000.0} sec)"
405
+ puts
406
+ end
407
+
408
+ $rd.keywords = SQL_KEYWORDS + Conn.tables
409
+ end
410
+
411
+ DEFAULT_PAGE_LENGTH = 37
412
+
413
+ $output = nil
414
+ $input = nil
415
+ $page_len = DEFAULT_PAGE_LENGTH
416
+ PROMPT = "dbi => "
417
+ PROMPT_CONT = "dbi -> "
418
+ INPUT = " >> "
419
+
420
+ SQL_KEYWORDS = %w(
421
+ INSERT DELETE UPDATE SELECT FROM WHERE IN LIKE SET VALUES INTO
422
+ CREATE TABLE DROP
423
+ COMMIT ROLLBACK
424
+ CHAR VARCHAR VARCHAR2 INT INTEGER NUMBER FLOAT REAL LONG CLOB BLOB DECIMAL
425
+ DBCLOB DBBLOB
426
+ )
427
+
428
+ # ---------------------------------------------------------------------------
429
+
430
+ opts = GetoptLong.new(
431
+ ["--file", "-f", GetoptLong::REQUIRED_ARGUMENT ]
432
+ )
433
+ opts.each do |opt, arg|
434
+ case opt
435
+ when "--file"
436
+ $input_file_name = arg
437
+ end
438
+ end
439
+
440
+ if ARGV.size < 1 or ARGV.size > 3
441
+ puts
442
+ puts "USAGE: #{$0} [--file file] driver_url [user [password] ]"
443
+ puts
444
+
445
+ puts "Available driver and datasources:"
446
+ puts
447
+ for driver in DBI.available_drivers do
448
+ puts driver
449
+ begin
450
+ ds = DBI.data_sources(driver)
451
+ for datasource in ds
452
+ puts " " + datasource
453
+ end
454
+ rescue => err
455
+ end
456
+ puts
457
+ end
458
+ puts
459
+
460
+ exit 1
461
+ else
462
+ DRIVER_URL = ARGV.shift
463
+ USER = ARGV.shift
464
+ PASS = ARGV.shift
465
+ end
466
+
467
+ puts
468
+ begin
469
+ Conn = DBI.connect(DRIVER_URL, USER, PASS)
470
+ print "CONNECT TO #{DRIVER_URL} "
471
+ print "USER #{USER} " unless USER.nil?
472
+ print "PASS #{PASS} " unless PASS.nil?
473
+ print "\n"
474
+
475
+ rescue DBI::Error, DBI::Warning => err
476
+ p err
477
+ exit
478
+ end
479
+
480
+ puts
481
+
482
+ $rd = ReadlineControl.new
483
+ $rd.keywords = SQL_KEYWORDS + Conn.tables
484
+
485
+ cmd = Command.new
486
+ act = Actions.new
487
+
488
+ # --file option
489
+ if $input_file_name
490
+ def $input_file_name.post_match
491
+ $input_file_name
492
+ end
493
+ act.input($input_file_name)
494
+ end
495
+
496
+ # Main-Loop -----------------------------------
497
+
498
+ loop do
499
+ line = cmd.readCommand
500
+
501
+ $output.puts line unless $output.nil?
502
+
503
+ begin
504
+ if line =~ /^\\/ then
505
+ # Internal Command
506
+ act.dispatchCommand(line)
507
+ else
508
+ # SQL Command
509
+ executeSQL(line)
510
+ end
511
+ rescue DBI::Error => err
512
+ puts
513
+ puts err.message
514
+ p err.backtrace if $DEBUG
515
+ puts
516
+ end
517
+ end
518
+