rdbi-driver-postgresql 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
data/LICENCE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT Licence
2
+
3
+ Copyright (c) 2010 Pistos
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT Licence
2
+
3
+ Copyright (c) 2010 Pistos
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,17 @@
1
+ = rdbi-dbd-postgresql
2
+
3
+ The PostgreSQL database driver for RDBI.
4
+
5
+ == Requirements
6
+
7
+ * Ruby 1.8.7+
8
+ * "pg" gem, version 0.9.0
9
+ * "rdbi" gem
10
+
11
+ == Copyright
12
+
13
+ Copyright (c) 2010 Pistos. See LICENCE for details.
14
+
15
+ == Acknowledgements
16
+
17
+ Thanks to Erik Hollensbe for sharing in-depth knowledge about RDBI and helping debug.
data/Rakefile ADDED
@@ -0,0 +1,62 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "rdbi-driver-postgresql"
8
+ gem.summary = %Q{PostgreSQL driver for RDBI}
9
+ gem.description = %Q{PostgreSQL driver for RDBI}
10
+ gem.email = "rdbi@pistos.oib.com"
11
+ gem.homepage = "http://github.com/Pistos/rdbi-dbd-postgresql"
12
+ gem.authors = [ "Pistos", "Erik Hollensbe" ]
13
+
14
+ gem.add_development_dependency 'test-unit'
15
+ gem.add_development_dependency 'rdoc'
16
+ gem.add_development_dependency 'rdbi-dbrc'
17
+
18
+ gem.add_dependency 'rdbi'
19
+ gem.add_dependency 'pg', '= 0.9.0'
20
+ gem.add_dependency 'methlab'
21
+ gem.add_dependency 'epoxy', '>= 0.3.1'
22
+
23
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
24
+ end
25
+ Jeweler::GemcutterTasks.new
26
+ rescue LoadError
27
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
28
+ end
29
+
30
+ require 'rake/testtask'
31
+ Rake::TestTask.new(:test) do |test|
32
+ test.libs << 'lib' << 'test'
33
+ test.pattern = 'test/**/test_*.rb'
34
+ test.verbose = true
35
+ end
36
+
37
+ begin
38
+ require 'rcov/rcovtask'
39
+ Rcov::RcovTask.new do |test|
40
+ test.libs << 'test'
41
+ test.pattern = 'test/**/test_*.rb'
42
+ test.verbose = true
43
+ end
44
+ rescue LoadError
45
+ task :rcov do
46
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
47
+ end
48
+ end
49
+
50
+ task :test => :check_dependencies
51
+
52
+ task :default => :test
53
+
54
+ require 'rdoc/task'
55
+ RDoc::Task.new do |rdoc|
56
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
57
+
58
+ rdoc.rdoc_dir = 'rdoc'
59
+ rdoc.title = "rdbi-dbd-postgresql #{version}"
60
+ rdoc.rdoc_files.include('README*')
61
+ rdoc.rdoc_files.include('lib/**/*.rb')
62
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.9.0
@@ -0,0 +1,314 @@
1
+ require 'rdbi'
2
+ require 'epoxy'
3
+ require 'methlab'
4
+ gem 'pg', '= 0.9.0'
5
+ require 'pg'
6
+
7
+ class RDBI::Driver::PostgreSQL < RDBI::Driver
8
+ def initialize( *args )
9
+ super( Database, *args )
10
+ end
11
+ end
12
+
13
+ class RDBI::Driver::PostgreSQL < RDBI::Driver
14
+ class Database < RDBI::Database
15
+ extend MethLab
16
+
17
+ attr_accessor :pg_conn
18
+
19
+ def initialize( *args )
20
+ super( *args )
21
+ self.database_name = @connect_args[:dbname] || @connect_args[:database] || @connect_args[:db]
22
+ @pg_conn = PGconn.new(
23
+ @connect_args[:host] || @connect_args[:hostname],
24
+ @connect_args[:port],
25
+ @connect_args[:options],
26
+ @connect_args[:tty],
27
+ self.database_name,
28
+ @connect_args[:user] || @connect_args[:username],
29
+ @connect_args[:password] || @connect_args[:auth]
30
+ )
31
+
32
+ @preprocess_quoter = proc do |x, named, indexed|
33
+ @pg_conn.escape_string((named[x] || indexed[x]).to_s)
34
+ end
35
+ end
36
+
37
+ def disconnect
38
+ @pg_conn.close
39
+ super
40
+ end
41
+
42
+ def transaction( &block )
43
+ if in_transaction?
44
+ raise RDBI::TransactionError.new( "Already in transaction (not supported by PostgreSQL)" )
45
+ end
46
+ execute 'BEGIN'
47
+ super &block
48
+ end
49
+
50
+ def rollback
51
+ if ! in_transaction?
52
+ raise RDBI::TransactionError.new( "Cannot rollback when not in a transaction" )
53
+ end
54
+ execute 'ROLLBACK'
55
+ super
56
+ end
57
+ def commit
58
+ if ! in_transaction?
59
+ raise RDBI::TransactionError.new( "Cannot commit when not in a transaction" )
60
+ end
61
+ execute 'COMMIT'
62
+ super
63
+ end
64
+
65
+ def new_statement( query )
66
+ Statement.new( query, self )
67
+ end
68
+
69
+ def table_schema( table_name, pg_schema = 'public' )
70
+ info_row = execute(
71
+ "SELECT table_type FROM information_schema.tables WHERE table_schema = ? AND table_name = ?",
72
+ pg_schema,
73
+ table_name
74
+ ).fetch( :all )[ 0 ]
75
+ if info_row.nil?
76
+ return nil
77
+ end
78
+
79
+ sch = RDBI::Schema.new( [], [] )
80
+ sch.tables << table_name.to_sym
81
+
82
+ case info_row[ 0 ]
83
+ when 'BASE TABLE'
84
+ sch.type = :table
85
+ when 'VIEW'
86
+ sch.type = :view
87
+ end
88
+
89
+ execute( "SELECT column_name, data_type, is_nullable FROM information_schema.columns WHERE table_schema = ? AND table_name = ?",
90
+ pg_schema,
91
+ table_name
92
+ ).fetch( :all ).each do |row|
93
+ col = RDBI::Column.new
94
+ col.name = row[0].to_sym
95
+ col.type = row[1].to_sym
96
+ # TODO: ensure this ruby_type is solid, especially re: dates and times
97
+ col.ruby_type = row[1].to_sym
98
+ col.nullable = row[2] == "YES"
99
+ sch.columns << col
100
+ end
101
+
102
+ sch
103
+ end
104
+
105
+ def schema( pg_schema = 'public' )
106
+ schemata = []
107
+ execute( "SELECT table_name FROM information_schema.tables WHERE table_schema = '#{pg_schema}';" ).fetch( :all ).each do |row|
108
+ schemata << table_schema( row[0], pg_schema )
109
+ end
110
+ schemata
111
+ end
112
+
113
+ def ping
114
+ start = Time.now
115
+ rows = begin
116
+ execute("SELECT 1").result_count
117
+ rescue PGError => e
118
+ # XXX Sorry this sucks. PGconn is completely useless without a
119
+ # connection... like asking it if it's connected.
120
+ raise RDBI::DisconnectedError.new(e.message)
121
+ end
122
+
123
+ stop = Time.now
124
+
125
+ if rows > 0
126
+ stop.to_i - start.to_i
127
+ else
128
+ raise RDBI::DisconnectedError, "disconnected during ping"
129
+ end
130
+ end
131
+ end
132
+
133
+ class Cursor < RDBI::Cursor
134
+ def initialize(handle, schema)
135
+ super(handle)
136
+ @index = 0
137
+ @stub_datetime = DateTime.now.strftime( " %z" )
138
+ @schema = schema
139
+ end
140
+
141
+ def fetch(count=1)
142
+ return [] if last_row?
143
+ a = []
144
+ count.times { a.push(next_row) }
145
+ return a
146
+ end
147
+
148
+ def next_row
149
+ val = @handle[@index].values
150
+ @index += 1
151
+ fix_dates(val)
152
+ end
153
+
154
+ def result_count
155
+ @handle.num_tuples
156
+ end
157
+
158
+ def affected_count
159
+ @handle.cmd_tuples
160
+ end
161
+
162
+ def first
163
+ fix_dates(@handle[0].values)
164
+ end
165
+
166
+ def last
167
+ fix_dates(@handle[-1].values)
168
+ end
169
+
170
+ def rest
171
+ oindex, @index = @index, result_count-1
172
+ fix_dates(fetch_range(oindex, @index))
173
+ end
174
+
175
+ def all
176
+ fix_dates(fetch_range(0, result_count-1))
177
+ end
178
+
179
+ def [](index)
180
+ fix_dates(@handle[index].values)
181
+ end
182
+
183
+ def last_row?
184
+ @index == result_count
185
+ end
186
+
187
+ def rewind
188
+ @index = 0
189
+ end
190
+
191
+ def empty?
192
+ result_count == 0
193
+ end
194
+
195
+ def finish
196
+ @handle.clear
197
+ end
198
+
199
+ protected
200
+
201
+ def fetch_range(start, stop)
202
+ # XXX when did PGresult get so stupid?
203
+ ary = []
204
+ (start..stop).to_a.each do |i|
205
+ row = []
206
+ @handle.num_fields.times do |j|
207
+ row[ j ] = @handle.getvalue( i, j )
208
+ end
209
+
210
+ ary.push row
211
+ end
212
+ # XXX end stupid rectifier.
213
+
214
+ return ary
215
+ end
216
+
217
+ def fix_dates(values)
218
+ # probably a better way to do this, but at least it's happening on fetch.
219
+ retval = []
220
+ values.each_with_index do |val, x|
221
+ if val.kind_of?(Array)
222
+ newval = []
223
+ val.each_with_index do |col, i|
224
+ if !col.nil? and @schema.columns[i].type == 'timestamp without time zone'
225
+ col << @stub_datetime
226
+ end
227
+
228
+ newval.push(col)
229
+ end
230
+ retval.push(newval)
231
+ else
232
+ if !val.nil? and @schema.columns[x].type == 'timestamp without time zone'
233
+ val << @stub_datetime
234
+ end
235
+ retval.push(val)
236
+ end
237
+ end
238
+ return retval
239
+ end
240
+ end
241
+
242
+ class Statement < RDBI::Statement
243
+ extend MethLab
244
+
245
+ attr_accessor :pg_result
246
+ attr_threaded_accessor :stmt_name
247
+
248
+ def initialize( query, dbh )
249
+ super( query, dbh )
250
+ @stmt_name = Time.now.to_f.to_s
251
+
252
+ ep = Epoxy.new( query )
253
+ @index_map = ep.indexed_binds
254
+ query = ep.quote(@index_map.compact.inject({}) { |x,y| x.merge({ y => nil }) }) do |x|
255
+ case x
256
+ when Integer
257
+ "$#{x+1}"
258
+ when Symbol
259
+ num = @index_map.index(x)
260
+ "$#{num+1}"
261
+ end
262
+ end
263
+
264
+ @pg_result = dbh.pg_conn.prepare(
265
+ @stmt_name,
266
+ query
267
+ )
268
+
269
+ # @input_type_map initialized in superclass
270
+ @output_type_map = RDBI::Type.create_type_hash( RDBI::Type::Out )
271
+ @output_type_map[ :bigint ] = RDBI::Type.filterlist( RDBI::Type::Filters::STR_TO_INT )
272
+ end
273
+
274
+ # Returns an Array of things used to fill out the parameters to RDBI::Result.new
275
+ def new_execution( *binds )
276
+ # FIXME move to RDBI::Util or something.
277
+ hashes, binds = binds.partition { |x| x.kind_of?(Hash) }
278
+ hash = hashes.inject({}) { |x, y| x.merge(y) }
279
+ hash.keys.each do |key|
280
+ if index = @index_map.index(key)
281
+ binds.insert(index, hash[key])
282
+ end
283
+ end
284
+
285
+ pg_result = @dbh.pg_conn.exec_prepared( @stmt_name, binds )
286
+
287
+ columns = []
288
+ stub_datetime = DateTime.now.strftime( " %z" )
289
+ (0...pg_result.num_fields).each do |i|
290
+ c = RDBI::Column.new
291
+ c.name = pg_result.fname( i ).to_sym
292
+ c.type = @dbh.pg_conn.exec(
293
+ "SELECT format_type( #{ pg_result.ftype(i) }, #{ pg_result.fmod(i) } )"
294
+ )[ 0 ].values[ 0 ]
295
+ if c.type.start_with? 'timestamp'
296
+ c.ruby_type = 'timestamp'.to_sym
297
+ else
298
+ c.ruby_type = c.type.to_sym
299
+ end
300
+ columns << c
301
+ end
302
+
303
+ this_schema = RDBI::Schema.new
304
+ this_schema.columns = columns
305
+
306
+ [ Cursor.new(pg_result, this_schema), this_schema, @output_type_map ]
307
+ end
308
+
309
+ def finish
310
+ @pg_result.clear
311
+ super
312
+ end
313
+ end
314
+ end
@@ -0,0 +1,71 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{rdbi-driver-postgresql}
8
+ s.version = "0.9.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Pistos", "Erik Hollensbe"]
12
+ s.date = %q{2010-08-21}
13
+ s.description = %q{PostgreSQL driver for RDBI}
14
+ s.email = %q{rdbi@pistos.oib.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ "LICENCE",
21
+ "LICENSE",
22
+ "README.rdoc",
23
+ "Rakefile",
24
+ "VERSION",
25
+ "lib/rdbi/driver/postgresql.rb",
26
+ "rdbi-driver-postgresql.gemspec",
27
+ "test/helper.rb",
28
+ "test/test_database.rb"
29
+ ]
30
+ s.homepage = %q{http://github.com/Pistos/rdbi-dbd-postgresql}
31
+ s.rdoc_options = ["--charset=UTF-8"]
32
+ s.require_paths = ["lib"]
33
+ s.rubygems_version = %q{1.3.7}
34
+ s.summary = %q{PostgreSQL driver for RDBI}
35
+ s.test_files = [
36
+ "test/helper.rb",
37
+ "test/test_database.rb"
38
+ ]
39
+
40
+ if s.respond_to? :specification_version then
41
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
42
+ s.specification_version = 3
43
+
44
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
45
+ s.add_development_dependency(%q<test-unit>, [">= 0"])
46
+ s.add_development_dependency(%q<rdoc>, [">= 0"])
47
+ s.add_development_dependency(%q<rdbi-dbrc>, [">= 0"])
48
+ s.add_runtime_dependency(%q<rdbi>, [">= 0"])
49
+ s.add_runtime_dependency(%q<pg>, ["= 0.9.0"])
50
+ s.add_runtime_dependency(%q<methlab>, [">= 0"])
51
+ s.add_runtime_dependency(%q<epoxy>, [">= 0.3.1"])
52
+ else
53
+ s.add_dependency(%q<test-unit>, [">= 0"])
54
+ s.add_dependency(%q<rdoc>, [">= 0"])
55
+ s.add_dependency(%q<rdbi-dbrc>, [">= 0"])
56
+ s.add_dependency(%q<rdbi>, [">= 0"])
57
+ s.add_dependency(%q<pg>, ["= 0.9.0"])
58
+ s.add_dependency(%q<methlab>, [">= 0"])
59
+ s.add_dependency(%q<epoxy>, [">= 0.3.1"])
60
+ end
61
+ else
62
+ s.add_dependency(%q<test-unit>, [">= 0"])
63
+ s.add_dependency(%q<rdoc>, [">= 0"])
64
+ s.add_dependency(%q<rdbi-dbrc>, [">= 0"])
65
+ s.add_dependency(%q<rdbi>, [">= 0"])
66
+ s.add_dependency(%q<pg>, ["= 0.9.0"])
67
+ s.add_dependency(%q<methlab>, [">= 0"])
68
+ s.add_dependency(%q<epoxy>, [">= 0.3.1"])
69
+ end
70
+ end
71
+
data/test/helper.rb ADDED
@@ -0,0 +1,41 @@
1
+ require 'rubygems'
2
+ gem 'test-unit'
3
+ require 'test/unit'
4
+ require 'fileutils'
5
+
6
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
7
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
8
+ gem 'rdbi-dbrc'
9
+ require 'rdbi-dbrc'
10
+ require 'rdbi/driver/postgresql'
11
+
12
+ class Test::Unit::TestCase
13
+
14
+ SQL = [
15
+ 'DROP TABLE IF EXISTS foo',
16
+ 'DROP TABLE IF EXISTS bar',
17
+ 'DROP TABLE IF EXISTS time_test',
18
+ 'DROP TABLE IF EXISTS ordinals',
19
+ 'create table foo (bar integer)',
20
+ 'create table bar (foo varchar, bar integer)',
21
+ 'create table time_test (my_date timestamp)',
22
+ 'CREATE TABLE ordinals ( id SERIAL PRIMARY KEY, cardinal INTEGER, s VARCHAR )',
23
+ "INSERT INTO ordinals ( cardinal, s ) VALUES ( 1, 'first' )",
24
+ "INSERT INTO ordinals ( cardinal, s ) VALUES ( 2, 'second' )",
25
+ "INSERT INTO ordinals ( cardinal, s ) VALUES ( 3, 'third' )",
26
+ ]
27
+
28
+ def new_database
29
+ RDBI::DBRC.connect(:postgresql_test)
30
+ end
31
+
32
+ def init_database
33
+ dbh = new_database
34
+ SQL.each { |query| dbh.execute(query) }
35
+ return dbh
36
+ end
37
+
38
+ def role
39
+ RDBI::DBRC.roles[:postgresql_test]
40
+ end
41
+ end
@@ -0,0 +1,316 @@
1
+ require 'helper'
2
+
3
+ class TestDatabase < Test::Unit::TestCase
4
+
5
+ attr_accessor :dbh
6
+
7
+ def teardown
8
+ @dbh.disconnect if @dbh && @dbh.connected?
9
+ end
10
+
11
+ def test_01_connect
12
+ self.dbh = new_database
13
+ assert dbh
14
+ assert_kind_of( RDBI::Driver::PostgreSQL::Database, dbh )
15
+ assert_kind_of( RDBI::Database, dbh )
16
+ assert_equal( dbh.database_name, role[:database] )
17
+ dbh.disconnect
18
+ assert ! dbh.connected?
19
+ end
20
+
21
+ def test_02_ping
22
+ self.dbh = init_database
23
+
24
+ my_role = role.dup
25
+ driver = my_role.delete(:driver)
26
+
27
+ assert_kind_of(Numeric, dbh.ping)
28
+ assert_kind_of(Numeric, RDBI.ping(driver, my_role))
29
+ dbh.disconnect
30
+
31
+ assert_raises(RDBI::DisconnectedError.new("not connected")) do
32
+ dbh.ping
33
+ end
34
+
35
+ # XXX This should still work because it connects. Obviously, testing a
36
+ # downed database is gonna be pretty hard.
37
+ assert_kind_of(Numeric, RDBI.ping(driver, my_role))
38
+ end
39
+
40
+ def test_03_execute
41
+ self.dbh = init_database
42
+ res = dbh.execute( "insert into foo (bar) values (?)", 1 )
43
+ assert res
44
+ assert_kind_of( RDBI::Result, res )
45
+ assert_equal( 1, res.affected_count )
46
+
47
+ res = dbh.execute( "select * from foo" )
48
+ assert res
49
+ assert_kind_of( RDBI::Result, res )
50
+ assert_equal( [[1]], res.fetch(:all) )
51
+
52
+ rows = res.as( :Struct ).fetch( :all )
53
+ row = rows[ 0 ]
54
+ assert_equal( 1, row.bar )
55
+
56
+ res = dbh.execute( "select count(*) from foo" )
57
+ assert res
58
+ assert_kind_of( RDBI::Result, res )
59
+ assert_equal( [[1]], res.fetch(:all) )
60
+ row = res.as( :Array ).fetch( :first )
61
+ assert_equal 1, row[ 0 ]
62
+
63
+ res = dbh.execute( "SELECT 5" )
64
+ assert res
65
+ assert_kind_of( RDBI::Result, res )
66
+ row = res.as( :Array ).fetch( :first )
67
+ assert_equal 5, row[ 0 ]
68
+
69
+ time_str = DateTime.now.strftime( "%Y-%m-%d %H:%M:%S %z" )
70
+ res = dbh.execute( "SELECT 5, TRUE, 'hello', '#{time_str}'::TIMESTAMP" )
71
+ assert res
72
+ assert_kind_of( RDBI::Result, res )
73
+ row = res.fetch( :all )[ 0 ]
74
+ assert_equal 5, row[ 0 ]
75
+ assert_equal true, row[ 1 ]
76
+ assert_equal 'hello', row[ 2 ]
77
+ assert_equal DateTime.parse( time_str ), row[ 3 ]
78
+ end
79
+
80
+ def test_04_prepare
81
+ self.dbh = init_database
82
+
83
+ sth = dbh.prepare( "insert into foo (bar) values (?)" )
84
+ assert sth
85
+ assert_kind_of( RDBI::Statement, sth )
86
+ assert_respond_to( sth, :execute )
87
+
88
+ 5.times do
89
+ res = sth.execute( 1 )
90
+ assert_equal( 1, res.affected_count )
91
+ end
92
+
93
+ assert_equal( dbh.last_statement.object_id, sth.object_id )
94
+
95
+ sth2 = dbh.prepare( "select * from foo" )
96
+ assert sth
97
+ assert_kind_of( RDBI::Statement, sth )
98
+ assert_respond_to( sth, :execute )
99
+
100
+ res = sth2.execute
101
+ assert res
102
+ assert_kind_of( RDBI::Result, res )
103
+ assert_equal( [[1]] * 5, res.fetch(:all) )
104
+
105
+ sth.execute 1
106
+
107
+ res = sth2.execute
108
+ assert res
109
+ assert_kind_of( RDBI::Result, res )
110
+ assert_equal( [[1]] * 6, res.fetch(:all) )
111
+
112
+ sth.finish
113
+ sth2.finish
114
+ end
115
+
116
+ def test_05_transaction
117
+ self.dbh = init_database
118
+
119
+ dbh.transaction do
120
+ assert dbh.in_transaction?
121
+ 5.times { dbh.execute( "insert into foo (bar) values (?)", 1 ) }
122
+ dbh.rollback
123
+ assert ! dbh.in_transaction?
124
+ end
125
+
126
+ assert ! dbh.in_transaction?
127
+
128
+ assert_equal( [], dbh.execute("select * from foo").fetch(:all) )
129
+
130
+ dbh.transaction do
131
+ assert dbh.in_transaction?
132
+ 5.times { dbh.execute("insert into foo (bar) values (?)", 1) }
133
+ assert_equal( [[1]] * 5, dbh.execute("select * from foo").fetch(:all) )
134
+ dbh.commit
135
+ assert ! dbh.in_transaction?
136
+ end
137
+
138
+ assert ! dbh.in_transaction?
139
+
140
+ assert_equal( [[1]] * 5, dbh.execute("select * from foo").fetch(:all) )
141
+
142
+ dbh.transaction do
143
+ assert dbh.in_transaction?
144
+ assert_raises( RDBI::TransactionError ) do
145
+ dbh.transaction do
146
+ end
147
+ end
148
+ end
149
+
150
+ # Not in a transaction
151
+
152
+ assert_raises( RDBI::TransactionError ) do
153
+ dbh.rollback
154
+ end
155
+
156
+ assert_raises( RDBI::TransactionError ) do
157
+ dbh.commit
158
+ end
159
+ end
160
+
161
+ def test_06_preprocess_query
162
+ self.dbh = init_database
163
+ assert_equal(
164
+ "insert into foo (bar) values (1)",
165
+ dbh.preprocess_query( "insert into foo (bar) values (?)", 1 )
166
+ )
167
+ end
168
+
169
+ def test_07_schema
170
+ self.dbh = init_database
171
+
172
+ dbh.execute( "insert into bar (foo, bar) values (?, ?)", "foo", 1 )
173
+ res = dbh.execute( "select * from bar" )
174
+
175
+ assert res
176
+ assert res.schema
177
+ assert_kind_of( RDBI::Schema, res.schema )
178
+ assert res.schema.columns
179
+ res.schema.columns.each { |x| assert_kind_of(RDBI::Column, x) }
180
+ end
181
+
182
+ def test_08_datetime
183
+ self.dbh = init_database
184
+
185
+ dt = DateTime.now
186
+ dbh.execute( 'insert into time_test (my_date) values (?)', dt )
187
+ dt2 = dbh.execute( 'select * from time_test limit 1' ).fetch(1)[0][0]
188
+
189
+ assert_kind_of( DateTime, dt2 )
190
+ assert_equal( dt2.to_s, dt.to_s )
191
+
192
+ dbh.execute 'INSERT INTO time_test ( my_date ) VALUES ( NULL )'
193
+ dt3 = "not nil"
194
+ assert_nothing_raised do
195
+ dt3 = dbh.execute( 'SELECT * FROM time_test WHERE my_date IS NULL LIMIT 1' ).fetch( 1 )[0][0]
196
+ end
197
+ assert_nil dt3
198
+ end
199
+
200
+ def test_09_basic_schema
201
+ self.dbh = init_database
202
+ assert_respond_to( dbh, :schema )
203
+ schema = dbh.schema.sort_by { |x| x.tables[0].to_s }
204
+
205
+ tables = [ :bar, :foo, :ordinals, :time_test ]
206
+ columns = {
207
+ :bar => { :foo => 'character varying'.to_sym, :bar => :integer },
208
+ :foo => { :bar => :integer },
209
+ :time_test => { :my_date => 'timestamp without time zone'.to_sym },
210
+ :ordinals => {
211
+ :id => :integer,
212
+ :cardinal => :integer,
213
+ :s => 'character varying'.to_sym,
214
+ },
215
+ }
216
+
217
+ schema.each_with_index do |sch, x|
218
+ assert_kind_of( RDBI::Schema, sch )
219
+ assert_equal( sch.tables[0], tables[x] )
220
+
221
+ sch.columns.each do |col|
222
+ assert_kind_of( RDBI::Column, col )
223
+ assert_equal( columns[ tables[x] ][ col.name ], col.type )
224
+ end
225
+ end
226
+
227
+ result = dbh.execute( "SELECT id, cardinal FROM ordinals ORDER BY id" )
228
+ rows = result.fetch( :all, RDBI::Result::Driver::Array )
229
+ assert_kind_of( Fixnum, rows[ 0 ][ 0 ] )
230
+ assert_kind_of( Fixnum, rows[ 0 ][ 1 ] )
231
+ rows = result.fetch( :all, RDBI::Result::Driver::Struct )
232
+ assert_kind_of( Fixnum, rows[ 0 ][ :id ] )
233
+ assert_kind_of( Fixnum, rows[ 0 ][ :cardinal ] )
234
+ end
235
+
236
+ def test_10_table_schema
237
+ self.dbh = init_database
238
+ assert_respond_to( dbh, :table_schema )
239
+
240
+ schema = dbh.table_schema( :foo )
241
+ columns = schema.columns
242
+ assert_equal columns.size, 1
243
+ c = columns[ 0 ]
244
+ assert_equal c.name, :bar
245
+ assert_equal c.type, :integer
246
+
247
+ schema = dbh.table_schema( :bar )
248
+ columns = schema.columns
249
+ assert_equal columns.size, 2
250
+ columns.each do |c|
251
+ case c.name
252
+ when :foo
253
+ assert_equal c.type, 'character varying'.to_sym
254
+ when :bar
255
+ assert_equal c.type, :integer
256
+ end
257
+ end
258
+
259
+ assert_nil dbh.table_schema( :non_existent )
260
+ end
261
+
262
+ def test_11_named_binds
263
+ self.dbh = init_database
264
+
265
+ res = dbh.execute("select id, cardinal, s from ordinals where id = ?id", { :id => 1 })
266
+ assert(res)
267
+ assert_equal([[1, 1, 'first']], res.fetch(:all))
268
+
269
+ res = dbh.execute("select id, cardinal, s from ordinals where id = ?id and cardinal = ?", { :id => 1 }, 1)
270
+ assert(res)
271
+ assert_equal([[1, 1, 'first']], res.fetch(:all))
272
+
273
+ res = dbh.execute("select id, cardinal, s from ordinals where id = ?id and cardinal = ?", 1, { :id => 1 })
274
+ assert(res)
275
+ assert_equal([[1, 1, 'first']], res.fetch(:all))
276
+ end
277
+
278
+ def test_12_struct_select
279
+ self.dbh = init_database
280
+
281
+ results = dbh.execute("select id, cardinal, s from ordinals order by id").as(:Struct).fetch(:all)
282
+
283
+ assert(results)
284
+ assert_kind_of(Array, results)
285
+ assert_equal(results[0].id, 1)
286
+ assert_equal(results[0].cardinal, 1)
287
+ assert_equal(results[0].s, 'first')
288
+ assert_equal(results[1].id, 2)
289
+ assert_equal(results[1].cardinal, 2)
290
+ assert_equal(results[1].s, 'second')
291
+ assert_equal(results[2].id, 3)
292
+ assert_equal(results[2].cardinal, 3)
293
+ assert_equal(results[2].s, 'third')
294
+
295
+ results = dbh.execute("select * from ordinals order by id").as(:Struct).fetch(:all)
296
+
297
+ assert(results)
298
+ assert_kind_of(Array, results)
299
+ assert_equal(results[0].id, 1)
300
+ assert_equal(results[0].cardinal, 1)
301
+ assert_equal(results[0].s, 'first')
302
+ assert_equal(results[1].id, 2)
303
+ assert_equal(results[1].cardinal, 2)
304
+ assert_equal(results[1].s, 'second')
305
+ assert_equal(results[2].id, 3)
306
+ assert_equal(results[2].cardinal, 3)
307
+ assert_equal(results[2].s, 'third')
308
+
309
+ result = dbh.execute("select * from ordinals order by id").as(:Struct).fetch(:first)
310
+ assert(result)
311
+ assert_kind_of(Struct, result)
312
+ assert_equal(result.id, 1)
313
+ assert_equal(result.cardinal, 1)
314
+ assert_equal(result.s, 'first')
315
+ end
316
+ end
metadata ADDED
@@ -0,0 +1,179 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rdbi-driver-postgresql
3
+ version: !ruby/object:Gem::Version
4
+ hash: 59
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 9
9
+ - 0
10
+ version: 0.9.0
11
+ platform: ruby
12
+ authors:
13
+ - Pistos
14
+ - Erik Hollensbe
15
+ autorequire:
16
+ bindir: bin
17
+ cert_chain: []
18
+
19
+ date: 2010-08-21 00:00:00 -04:00
20
+ default_executable:
21
+ dependencies:
22
+ - !ruby/object:Gem::Dependency
23
+ name: test-unit
24
+ prerelease: false
25
+ requirement: &id001 !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ">="
29
+ - !ruby/object:Gem::Version
30
+ hash: 3
31
+ segments:
32
+ - 0
33
+ version: "0"
34
+ type: :development
35
+ version_requirements: *id001
36
+ - !ruby/object:Gem::Dependency
37
+ name: rdoc
38
+ prerelease: false
39
+ requirement: &id002 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ hash: 3
45
+ segments:
46
+ - 0
47
+ version: "0"
48
+ type: :development
49
+ version_requirements: *id002
50
+ - !ruby/object:Gem::Dependency
51
+ name: rdbi-dbrc
52
+ prerelease: false
53
+ requirement: &id003 !ruby/object:Gem::Requirement
54
+ none: false
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ hash: 3
59
+ segments:
60
+ - 0
61
+ version: "0"
62
+ type: :development
63
+ version_requirements: *id003
64
+ - !ruby/object:Gem::Dependency
65
+ name: rdbi
66
+ prerelease: false
67
+ requirement: &id004 !ruby/object:Gem::Requirement
68
+ none: false
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ hash: 3
73
+ segments:
74
+ - 0
75
+ version: "0"
76
+ type: :runtime
77
+ version_requirements: *id004
78
+ - !ruby/object:Gem::Dependency
79
+ name: pg
80
+ prerelease: false
81
+ requirement: &id005 !ruby/object:Gem::Requirement
82
+ none: false
83
+ requirements:
84
+ - - "="
85
+ - !ruby/object:Gem::Version
86
+ hash: 59
87
+ segments:
88
+ - 0
89
+ - 9
90
+ - 0
91
+ version: 0.9.0
92
+ type: :runtime
93
+ version_requirements: *id005
94
+ - !ruby/object:Gem::Dependency
95
+ name: methlab
96
+ prerelease: false
97
+ requirement: &id006 !ruby/object:Gem::Requirement
98
+ none: false
99
+ requirements:
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ hash: 3
103
+ segments:
104
+ - 0
105
+ version: "0"
106
+ type: :runtime
107
+ version_requirements: *id006
108
+ - !ruby/object:Gem::Dependency
109
+ name: epoxy
110
+ prerelease: false
111
+ requirement: &id007 !ruby/object:Gem::Requirement
112
+ none: false
113
+ requirements:
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ hash: 17
117
+ segments:
118
+ - 0
119
+ - 3
120
+ - 1
121
+ version: 0.3.1
122
+ type: :runtime
123
+ version_requirements: *id007
124
+ description: PostgreSQL driver for RDBI
125
+ email: rdbi@pistos.oib.com
126
+ executables: []
127
+
128
+ extensions: []
129
+
130
+ extra_rdoc_files:
131
+ - LICENSE
132
+ - README.rdoc
133
+ files:
134
+ - LICENCE
135
+ - LICENSE
136
+ - README.rdoc
137
+ - Rakefile
138
+ - VERSION
139
+ - lib/rdbi/driver/postgresql.rb
140
+ - rdbi-driver-postgresql.gemspec
141
+ - test/helper.rb
142
+ - test/test_database.rb
143
+ has_rdoc: true
144
+ homepage: http://github.com/Pistos/rdbi-dbd-postgresql
145
+ licenses: []
146
+
147
+ post_install_message:
148
+ rdoc_options:
149
+ - --charset=UTF-8
150
+ require_paths:
151
+ - lib
152
+ required_ruby_version: !ruby/object:Gem::Requirement
153
+ none: false
154
+ requirements:
155
+ - - ">="
156
+ - !ruby/object:Gem::Version
157
+ hash: 3
158
+ segments:
159
+ - 0
160
+ version: "0"
161
+ required_rubygems_version: !ruby/object:Gem::Requirement
162
+ none: false
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ hash: 3
167
+ segments:
168
+ - 0
169
+ version: "0"
170
+ requirements: []
171
+
172
+ rubyforge_project:
173
+ rubygems_version: 1.3.7
174
+ signing_key:
175
+ specification_version: 3
176
+ summary: PostgreSQL driver for RDBI
177
+ test_files:
178
+ - test/helper.rb
179
+ - test/test_database.rb