do_mysql 0.2.4 → 0.9.2

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.
@@ -1,65 +1,66 @@
1
- if `uname -sr` =~ /^Darwin/
2
- ENV["RC_ARCHS"] = `uname -m`.chomp
3
- unless File.exists?("/usr/local/mysql/lib/mysql")
4
- `sudo ln -s /usr/local/mysql/lib /usr/local/mysql/lib/mysql` rescue nil
5
- end
6
- end
1
+ if RUBY_PLATFORM =~ /darwin/
2
+ ENV["RC_ARCHS"] = `uname -m`.chomp if `uname -sr` =~ /^Darwin/
7
3
 
8
- # Figure out where mysql_config is
9
- if !`which mysql_config`.chomp.empty?
10
- @mysql_config_bin = "mysql_config"
11
- elsif !`which mysql_config5`.chomp.empty?
12
- @mysql_config_bin = "mysql_config5"
13
- else
14
- puts "Cannot find mysql_config in your path. Please enter a location: "
15
- location = gets.chomp
16
- if File.exists?(location)
17
- @mysql_config_bin = location
18
- else
19
- puts "Cannot find that file. Exiting."
20
- exit
21
- end
4
+ # On PowerPC the defaults are fine
5
+ ENV["RC_ARCHS"] = '' if `uname -m` =~ /^Power Macintosh/
22
6
  end
23
7
 
24
8
  require 'mkmf'
25
9
 
26
- def config_value(type)
27
- ENV["MYSQL_#{type.upcase}"] || mysql_config(type)
10
+ # All instances of mysql_config on PATH ...
11
+ def mysql_config_paths
12
+ ENV['PATH'].split(File::PATH_SEPARATOR).collect do |path|
13
+ [ "#{path}/mysql_config", "#{path}/mysql_config5" ].
14
+ detect { |bin| File.exist?(bin) }
15
+ end
28
16
  end
29
17
 
30
- @mysql_config = {}
31
-
32
- def mysql_config(type)
33
- return @mysql_config[type] if @mysql_config[type]
18
+ # The first mysql_config binary on PATH ...
19
+ def default_mysql_config_path
20
+ mysql_config_paths.compact.first
21
+ end
34
22
 
35
- sout = `#{@mysql_config_bin} --#{type}`
36
-
37
- unless $?.success?
38
- raise "mysql_config not found"
23
+ def default_prefix
24
+ if mc = default_mysql_config_path
25
+ File.dirname(File.dirname(mc))
26
+ else
27
+ "/usr/local"
39
28
  end
40
-
41
- @mysql_config[type] = sout.chomp[2..-1]
42
- @mysql_config[type]
43
29
  end
44
30
 
45
- $inc, $lib = dir_config('mysql', config_value('include'), config_value('libs_r'))
46
-
47
- def have_build_env
31
+ # Allow overriding path to mysql_config on command line using:
32
+ # ruby extconf.rb --with-mysql-config=/path/to/mysql_config
33
+ if RUBY_PLATFORM =~ /mswin|mingw/
34
+ dir_config('mysql')
35
+ have_header 'mysql.h' || exit(1)
36
+ have_library 'libmysql' || exit(1)
37
+ have_func('mysql_query', 'mysql.h') || exit(1)
38
+ have_func('mysql_ssl_set', 'mysql.h')
39
+ elsif mc = with_config('mysql-config', default_mysql_config_path)
40
+ mc = default_mysql_config_path if mc == true
41
+ cflags = `#{mc} --cflags`.chomp
42
+ exit 1 if $? != 0
43
+ libs = `#{mc} --libs`.chomp
44
+ exit 1 if $? != 0
45
+ $CPPFLAGS += ' ' + cflags
46
+ $libs = libs + " " + $libs
47
+ else
48
+ inc, lib = dir_config('mysql', default_prefix)
48
49
  libs = ['m', 'z', 'socket', 'nsl']
49
- while not find_library('mysqlclient', "mysql_query", config_value('libs'), $lib, "#{$lib}/mysql") do
50
- exit 1 if libs.empty?
51
- have_library(libs.shift)
52
- end
53
- true
50
+ lib_dirs =
51
+ [ lib, "/usr/lib", "/usr/local/lib", "/opt/local/lib" ].collect do |path|
52
+ [ path, "#{path}/mysql", "#{path}/mysql5/mysql" ]
53
+ end
54
+ find_library('mysqlclient', 'mysql_query', *lib_dirs.flatten) || exit(1)
55
+ find_header('mysql.h', *lib_dirs.flatten.map { |p| p.gsub('/lib', '/include') })
54
56
  end
55
57
 
56
- required_libraries = []
57
- desired_functions = %w(mysql_ssl_set)
58
+ unless RUBY_PLATFORM =~ /mswin|mingw/
59
+ have_header 'mysql.h'
60
+ have_library 'mysqlclient' || exit(1)
61
+ have_func 'mysql_query' || exit(1)
62
+ have_func 'mysql_ssl_set'
63
+ end
58
64
 
59
- if have_build_env
60
- $CFLAGS << ' -Wall '
61
- dir_config("mysql_c")
62
- create_makefile("mysql_c")
63
- else
64
- puts 'Could not find MySQL build environment (libraries & headers): Makefile not created'
65
- end
65
+ $CFLAGS << ' -Wall ' unless RUBY_PLATFORM =~ /mswin/
66
+ create_makefile('do_mysql_ext')
@@ -1,258 +1,26 @@
1
- require 'mysql_c'
1
+ require 'rubygems'
2
2
  require 'data_objects'
3
-
4
- module DataObject
5
- module Mysql
6
- TYPES = Hash[*Mysql_c.constants.select {|x| x.include?("MYSQL_TYPE")}.map {|x| [Mysql_c.const_get(x), x.gsub(/^MYSQL_TYPE_/, "")]}.flatten]
7
-
8
- QUOTE_STRING = "\""
9
- QUOTE_COLUMN = "`"
10
-
11
- class Connection < DataObject::Connection
12
-
13
- attr_reader :db
14
-
15
- def initialize(connection_string)
16
- @state = STATE_CLOSED
17
- @connection_string = connection_string
18
- opts = connection_string.split(" ")
19
- opts.each do |opt|
20
- k, v = opt.split("=")
21
- raise ArgumentError, "you specified an invalid connection component: #{opt}" unless k && v
22
- instance_variable_set("@#{k}", v)
23
- end
24
- end
25
-
26
- def change_database(database_name)
27
- @dbname = database_name
28
- @connection_string.gsub(/db_name=[^ ]*/, "db_name=#{database_name}")
29
- end
30
-
31
- def open
32
- @db = Mysql_c.mysql_init(nil)
33
- raise ConnectionFailed, "could not allocate a MySQL connection" unless @db
34
- conn = Mysql_c.mysql_real_connect(@db, @host, @user, @password, @dbname, @port || 0, @socket, @flags || 0)
35
- raise ConnectionFailed, "Unable to connect to database with provided connection string. \n#{Mysql_c.mysql_error(@db)}" unless conn
36
- @state = STATE_OPEN
37
- true
38
- end
39
-
40
- def close
41
- if @state == STATE_OPEN
42
- Mysql_c.mysql_close(@db)
43
- @state = STATE_CLOSED
44
- true
45
- else
46
- false
47
- end
48
- end
49
-
50
- def create_command(text)
51
- Command.new(self, text)
52
- end
53
-
54
- def begin_transaction
55
- Transaction.new(self)
56
- end
57
-
58
- end
59
-
60
- class Field
61
- attr_reader :name, :type
62
-
63
- def initialize(ptr)
64
- @name, @type = ptr.name.to_s, ptr.type.to_s
65
- end
66
- end
67
-
68
- class Transaction
69
-
70
- attr_reader :connection
71
-
72
- def initialize(conn)
73
- @connection = conn
74
- exec_sql("BEGIN")
75
- end
76
-
77
- # Commits the transaction
78
- def commit
79
- exec_sql("COMMIT")
80
- end
81
-
82
- # Rolls back the transaction
83
- def rollback(savepoint = nil)
84
- raise NotImplementedError, "MySQL does not support savepoints" if savepoint
85
- exec_sql("ROLLBACK")
86
- end
87
-
88
- # Creates a savepoint for rolling back later (not commonly supported)
89
- def save(name)
90
- raise NotImplementedError, "MySQL does not support savepoints"
91
- end
92
-
93
- def create_command(*args)
94
- @connection.create_command(*args)
95
- end
96
-
97
- protected
98
-
99
- def exec_sql(sql)
100
- @connection.logger.debug(sql)
101
- Mysql_c.mysql_query(@connection.db, sql)
102
- end
103
-
104
- end
105
-
106
- class Reader < DataObject::Reader
107
-
108
- def initialize(db, reader)
109
- @reader = reader
110
- unless @reader
111
- if Mysql_c.mysql_field_count(db) == 0
112
- @records_affected = Mysql_c.mysql_affected_rows(db)
113
- close
114
- else
115
- raise UnknownError, "An unknown error has occured while trying to process a MySQL query.\n#{Mysql_c.mysql_error(db)}"
116
- end
117
- else
118
- @field_count = @reader.field_count
119
- @state = STATE_OPEN
120
-
121
- @native_fields, @fields = Mysql_c.mysql_c_fetch_field_types(@reader, @field_count), Mysql_c.mysql_c_fetch_field_names(@reader, @field_count)
122
-
123
- raise UnknownError, "An unknown error has occured while trying to process a MySQL query. There were no fields in the resultset\n#{Mysql_c.mysql_error(db)}" if @native_fields.empty?
124
-
125
- @has_rows = !(@row = Mysql_c.mysql_c_fetch_row(@reader)).nil?
3
+ require 'do_jdbc-support' if RUBY_PLATFORM =~ /java/ # generic, shared JDBC support code
4
+ require 'do_mysql_ext' # the C/Java extension for this DO driver
5
+ require 'do_mysql/transaction'
6
+
7
+ if RUBY_PLATFORM =~ /java/
8
+ require 'do_jdbc/mysql' # the JDBC driver, packaged as a gem
9
+
10
+ # Another way of loading the JDBC Class. This seems to be more relaible
11
+ # than Class.forName() within the data_objects.Connection Java class,
12
+ # which is currently not working as expected.
13
+ require 'java'
14
+ import 'com.mysql.jdbc.Driver'
15
+
16
+ module DataObjects
17
+ module Mysql
18
+ class Connection
19
+ def self.pool_size
20
+ 20
126
21
  end
127
22
  end
128
-
129
- def close
130
- if @state == STATE_OPEN
131
- Mysql_c.mysql_free_result(@reader)
132
- @state = STATE_CLOSED
133
- true
134
- else
135
- false
136
- end
137
- end
138
-
139
- def name(col)
140
- super
141
- @fields[col]
142
- end
143
-
144
- def get_index(name)
145
- super
146
- @fields.index(name)
147
- end
148
-
149
- def null?(idx)
150
- super
151
- @row[idx] == nil
152
- end
153
-
154
- def current_row
155
- @row
156
- end
157
-
158
- def item(idx)
159
- super
160
- typecast(@row[idx], idx)
161
- end
162
-
163
- def next
164
- super
165
- @row = Mysql_c.mysql_c_fetch_row(@reader)
166
- close if @row.nil?
167
- @row ? true : nil
168
- end
169
-
170
- def each
171
- return unless has_rows?
172
-
173
- while(true) do
174
- yield
175
- break unless self.next
176
- end
177
- end
178
-
179
- protected
180
- def native_type(col)
181
- super
182
- TYPES[@native_fields[col].type]
183
- end
184
-
185
- def typecast(val, idx)
186
- return nil if val.nil? || val == "NULL"
187
- field = @native_fields[idx]
188
- case TYPES[field]
189
- when "NULL"
190
- nil
191
- when "TINY"
192
- val != "0"
193
- when "BIT"
194
- val.to_i(2)
195
- when "SHORT", "LONG", "INT24", "LONGLONG"
196
- val == '' ? nil : val.to_i
197
- when "DECIMAL", "NEWDECIMAL", "FLOAT", "DOUBLE", "YEAR"
198
- val.to_f
199
- when "TIMESTAMP", "DATETIME"
200
- DateTime.parse(val) rescue nil
201
- when "TIME"
202
- DateTime.parse(val).to_time rescue nil
203
- when "DATE"
204
- Date.parse(val) rescue nil
205
- else
206
- val
207
- end
208
- end
209
- end
210
-
211
- class Command < DataObject::Command
212
-
213
- def execute_reader(*args)
214
- super
215
- sql = escape_sql(args)
216
- @connection.logger.debug { sql }
217
- result = Mysql_c.mysql_query(@connection.db, sql)
218
- # TODO: Real Error
219
- raise QueryError, "Your query failed.\n#{Mysql_c.mysql_error(@connection.db)}\n#{@text}" unless result == 0
220
- reader = Reader.new(@connection.db, Mysql_c.mysql_use_result(@connection.db))
221
- if block_given?
222
- result = yield(reader)
223
- reader.close
224
- result
225
- else
226
- reader
227
- end
228
- end
229
-
230
- def execute_non_query(*args)
231
- super
232
- sql = escape_sql(args)
233
- @connection.logger.debug { sql }
234
- result = Mysql_c.mysql_query(@connection.db, sql)
235
- raise QueryError, "Your query failed.\n#{Mysql_c.mysql_error(@connection.db)}\n#{@text}" unless result == 0
236
- reader = Mysql_c.mysql_store_result(@connection.db)
237
- raise QueryError, "You called execute_non_query on a query: #{@text}" if reader
238
- rows_affected = Mysql_c.mysql_affected_rows(@connection.db)
239
- Mysql_c.mysql_free_result(reader)
240
- return ResultData.new(@connection, rows_affected, Mysql_c.mysql_insert_id(@connection.db))
241
- end
242
-
243
- def quote_time(value)
244
- # TIMESTAMP() used for both time and datetime columns
245
- quote_datetime(value)
246
- end
247
-
248
- def quote_datetime(value)
249
- "TIMESTAMP('#{value.strftime("%Y-%m-%d %H:%M:%S")}')"
250
- end
251
-
252
- def quote_date(value)
253
- "DATE('#{value.strftime("%Y-%m-%d")}')"
254
- end
255
23
  end
256
-
257
24
  end
25
+
258
26
  end
@@ -0,0 +1,44 @@
1
+
2
+ module DataObjects
3
+
4
+ module Mysql
5
+
6
+ class Transaction < DataObjects::Transaction
7
+
8
+ def finalize_transaction
9
+ cmd = "XA END '#{id}'"
10
+ connection.create_command(cmd).execute_non_query
11
+ end
12
+
13
+ def begin
14
+ cmd = "XA START '#{id}'"
15
+ connection.create_command(cmd).execute_non_query
16
+ end
17
+
18
+ def commit
19
+ cmd = "XA COMMIT '#{id}'"
20
+ connection.create_command(cmd).execute_non_query
21
+ end
22
+
23
+ def rollback
24
+ finalize_transaction
25
+ cmd = "XA ROLLBACK '#{id}'"
26
+ connection.create_command(cmd).execute_non_query
27
+ end
28
+
29
+ def rollback_prepared
30
+ cmd = "XA ROLLBACK '#{id}'"
31
+ connection.create_command(cmd).execute_non_query
32
+ end
33
+
34
+ def prepare
35
+ finalize_transaction
36
+ cmd = "XA PREPARE '#{id}'"
37
+ connection.create_command(cmd).execute_non_query
38
+ end
39
+
40
+ end
41
+
42
+ end
43
+
44
+ end
@@ -0,0 +1,241 @@
1
+ require 'pathname'
2
+ require Pathname(__FILE__).dirname.expand_path.parent + 'spec_helper'
3
+
4
+ describe DataObjects::Mysql do
5
+ include MysqlSpecHelpers
6
+
7
+ before :all do
8
+ setup_test_environment
9
+ end
10
+
11
+ it "should expose the proper DataObjects classes" do
12
+ DataObjects::Mysql.const_get('Connection').should_not be_nil
13
+ DataObjects::Mysql.const_get('Command').should_not be_nil
14
+ DataObjects::Mysql.const_get('Result').should_not be_nil
15
+ DataObjects::Mysql.const_get('Reader').should_not be_nil
16
+ end
17
+
18
+ it "should connect successfully via TCP" do
19
+ pending "Problems parsing regular connection URIs vs. JDBC URLs" if JRUBY
20
+ connection = DataObjects::Mysql::Connection.new("mysql://root@127.0.0.1:3306/do_mysql_test")
21
+ connection.should_not be_using_socket
22
+ end
23
+
24
+ #
25
+ # I comment this out partly to raise the issue for discussion. Socket files are afaik not supported under windows. Does this
26
+ # mean that we should test for it on unix boxes but not on windows boxes? Or does it mean that it should not be speced at all?
27
+ # It's not really a requirement, since all architectures that support MySQL also supports TCP connectsion, ne?
28
+ #
29
+ # it "should connect successfully via the socket file" do
30
+ # @connection = DataObjects::Mysql::Connection.new("mysql://root@localhost:3306/do_mysql_test/?socket=#{SOCKET_PATH}")
31
+ # @connection.should be_using_socket
32
+ # end
33
+
34
+ it "should return the current character set" do
35
+ pending "Problems parsing regular connection URIs vs. JDBC URLs" if JRUBY
36
+ connection = DataObjects::Mysql::Connection.new("mysql://root@localhost:3306/do_mysql_test")
37
+ connection.character_set.should == "utf8"
38
+ end
39
+
40
+ it "should support changing the character set" do
41
+ pending "Problems parsing regular connection URIs vs. JDBC URLs" if JRUBY
42
+ connection = DataObjects::Mysql::Connection.new("mysql://root@localhost:3306/do_mysql_test/?charset=latin1")
43
+ connection.character_set.should == "latin1"
44
+
45
+ @connection = DataObjects::Mysql::Connection.new("mysql://root@localhost:3306/do_mysql_test/?charset=utf8")
46
+ @connection.character_set.should == "utf8"
47
+ end
48
+
49
+ it "should raise an error when opened with an invalid server uri" do
50
+ pending "Problems parsing regular connection URIs vs. JDBC URLs" if JRUBY
51
+ def connecting_with(uri)
52
+ lambda { DataObjects::Mysql::Connection.new(uri) }
53
+ end
54
+
55
+ # Missing database name
56
+ connecting_with("mysql://root@localhost:3306/").should raise_error(MysqlError)
57
+
58
+ # Wrong port
59
+ connecting_with("mysql://root@localhost:666/").should raise_error(MysqlError)
60
+
61
+ # Bad Username
62
+ connecting_with("mysql://baduser@localhost:3306/").should raise_error(MysqlError)
63
+
64
+ # Bad Password
65
+ connecting_with("mysql://root:wrongpassword@localhost:3306/").should raise_error(MysqlError)
66
+
67
+ # Bad Database Name
68
+ connecting_with("mysql://root@localhost:3306/bad_database").should raise_error(MysqlError)
69
+
70
+ #
71
+ # Again, should socket even be speced if we don't support it across all platforms?
72
+ #
73
+ # Invalid Socket Path
74
+ #connecting_with("mysql://root@localhost:3306/do_mysql_test/?socket=/invalid/path/mysql.sock").should raise_error(MysqlError)
75
+ end
76
+ end
77
+
78
+ describe DataObjects::Mysql::Connection do
79
+ include MysqlSpecHelpers
80
+
81
+ before :all do
82
+ setup_test_environment
83
+ end
84
+
85
+ it "should raise an error when attempting to execute a bad query" do
86
+ lambda { @connection.create_command("INSERT INTO non_existant_table (tester) VALUES (1)").execute_non_query }.should raise_error(MysqlError)
87
+ lambda { @connection.create_command("SELECT * FROM non_existant table").execute_reader }.should raise_error(MysqlError)
88
+ end
89
+
90
+ end
91
+
92
+ describe DataObjects::Mysql::Reader do
93
+ include MysqlSpecHelpers
94
+
95
+ before :all do
96
+ setup_test_environment
97
+ end
98
+
99
+ it "should raise an error when you pass too many or too few types for the expected result set" do
100
+ lambda { select("SELECT name, fired_at FROM users", [String, DateTime, Integer]) }.should raise_error(MysqlError)
101
+ end
102
+
103
+ it "shouldn't raise an error when you pass NO types for the expected result set" do
104
+ lambda { select("SELECT name, fired_at FROM users", nil) }.should_not raise_error(MysqlError)
105
+ end
106
+
107
+ it "should return the proper number of fields" do
108
+ id = insert("INSERT INTO users (name) VALUES ('Billy Bob')")
109
+ select("SELECT id, name, fired_at FROM users WHERE id = ?", nil, id) do |reader|
110
+ reader.fields.size.should == 3
111
+ end
112
+ end
113
+
114
+ it "should raise an exception if .values is called after reading all available rows" do
115
+ select("SELECT * FROM widgets LIMIT 2") do |reader|
116
+ # select already calls next once for us
117
+ reader.next!
118
+ reader.next!
119
+
120
+ lambda { reader.values }.should raise_error(MysqlError)
121
+ end
122
+ end
123
+
124
+ it "should fetch the proper number of rows" do
125
+ ids = [
126
+ insert("INSERT INTO users (name) VALUES ('Slappy Wilson')"),
127
+ insert("INSERT INTO users (name) VALUES ('Jumpy Jones')")
128
+ ]
129
+
130
+ select("SELECT * FROM users WHERE id IN ?", nil, ids) do |reader|
131
+ # select already calls next once for us
132
+ reader.next!.should == true
133
+ reader.next!.should be_nil
134
+ end
135
+ end
136
+
137
+ it "should contain tainted strings" do
138
+ id = insert("INSERT INTO users (name) VALUES ('Cuppy Canes')")
139
+
140
+ select("SELECT name FROM users WHERE id = ?", nil, id) do |reader|
141
+ reader.values.first.should be_tainted
142
+ end
143
+
144
+ end
145
+
146
+ it "should return DB nulls as nil" do
147
+ id = insert("INSERT INTO users (name) VALUES (NULL)")
148
+ select("SELECT name from users WHERE name is null") do |reader|
149
+ reader.values[0].should == nil
150
+ end
151
+ end
152
+
153
+ it "should not convert empty strings to null" do
154
+ id = insert("INSERT INTO users (name) VALUES ('')")
155
+ select("SELECT name FROM users WHERE id = ?", [String], id) do |reader|
156
+ reader.values.first.should == ''
157
+ end
158
+ end
159
+
160
+ describe "Date, Time, and DateTime" do
161
+
162
+ it "should return DateTimes using the current locale's Time Zone" do
163
+ date = DateTime.now
164
+ id = insert("INSERT INTO users (name, fired_at) VALUES (?, ?)", 'Sam', date)
165
+ select("SELECT fired_at FROM users WHERE id = ?", [DateTime], id) do |reader|
166
+ reader.values.last.to_s.should == date.to_s
167
+ end
168
+ exec("DELETE FROM users WHERE id = ?", id)
169
+ end
170
+
171
+ now = DateTime.now
172
+
173
+ dates = [
174
+ now.new_offset( (-11 * 3600).to_r / 86400), # GMT -11:00
175
+ now.new_offset( (-9 * 3600 + 10 * 60).to_r / 86400), # GMT -9:10, contrived
176
+ now.new_offset( (-8 * 3600).to_r / 86400), # GMT -08:00
177
+ now.new_offset( (+3 * 3600).to_r / 86400), # GMT +03:00
178
+ now.new_offset( (+5 * 3600 + 30 * 60).to_r / 86400) # GMT +05:30 (New Delhi)
179
+ ]
180
+
181
+ dates.each do |date|
182
+ it "should return #{date.to_s} offset to the current locale's Time Zone if they were inserted using a different timezone" do
183
+ pending "We don't support non-local date input yet"
184
+
185
+ dates.each do |date|
186
+ id = insert("INSERT INTO users (name, fired_at) VALUES (?, ?)", 'Sam', date)
187
+
188
+ select("SELECT fired_at FROM users WHERE id = ?", [DateTime], id) do |reader|
189
+ reader.values.last.to_s.should == now.to_s
190
+ end
191
+
192
+ exec("DELETE FROM users WHERE id = ?", id)
193
+ end
194
+ end
195
+ end
196
+
197
+ end
198
+
199
+ describe "executing a non-query" do
200
+ it "should return a Result" do
201
+ command = @connection.create_command("INSERT INTO invoices (invoice_number) VALUES ('1234')")
202
+ result = command.execute_non_query
203
+ result.should be_kind_of(DataObjects::Mysql::Result)
204
+ end
205
+
206
+ it "should be able to determine the affected_rows" do
207
+ command = @connection.create_command("INSERT INTO invoices (invoice_number) VALUES ('1234')")
208
+ result = command.execute_non_query
209
+ result.to_i.should == 1
210
+ end
211
+
212
+ it "should yield the last inserted id" do
213
+ @connection.create_command("TRUNCATE TABLE invoices").execute_non_query
214
+
215
+ result = @connection.create_command("INSERT INTO invoices (invoice_number) VALUES ('1234')").execute_non_query
216
+ result.insert_id.should == 1
217
+
218
+ result = @connection.create_command("INSERT INTO invoices (invoice_number) VALUES ('3456')").execute_non_query
219
+ result.insert_id.should == 2
220
+ end
221
+
222
+ it "should be able to determine the affected_rows" do
223
+ [
224
+ "TRUNCATE TABLE invoices",
225
+ "INSERT INTO invoices (invoice_number) VALUES ('1234')",
226
+ "INSERT INTO invoices (invoice_number) VALUES ('1234')"
227
+ ].each { |q| @connection.create_command(q).execute_non_query }
228
+
229
+ result = @connection.create_command("UPDATE invoices SET invoice_number = '3456'").execute_non_query
230
+ result.to_i.should == 2
231
+ end
232
+
233
+ it "should raise an error when executing an invalid query" do
234
+ command = @connection.create_command("UPDwhoopsATE invoices SET invoice_number = '3456'")
235
+
236
+ lambda { command.execute_non_query }.should raise_error(Exception)
237
+ end
238
+
239
+ end
240
+
241
+ end