ruby-mysql 2.9.4 → 2.9.5

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of ruby-mysql might be problematic. Click here for more details.

data/lib/mysql.rb CHANGED
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2008-2010 TOMITA Masahiro
1
+ # Copyright (C) 2008-2012 TOMITA Masahiro
2
2
  # mailto:tommy@tmtm.org
3
3
 
4
4
  # MySQL connection class.
@@ -21,8 +21,6 @@ class Mysql
21
21
  MYSQL_TCP_PORT = 3306 # TCP socket port number
22
22
 
23
23
  attr_reader :charset # character set of MySQL connection
24
- attr_reader :affected_rows # number of affected records by insert/update/delete.
25
- attr_reader :warning_count # number of warnings for previous query
26
24
  attr_reader :protocol # :nodoc:
27
25
 
28
26
  attr_accessor :query_with_result
@@ -84,12 +82,9 @@ class Mysql
84
82
  @read_timeout = nil
85
83
  @write_timeout = nil
86
84
  @init_command = nil
87
- @affected_rows = nil
88
- @warning_count = 0
89
85
  @sqlstate = "00000"
90
86
  @query_with_result = true
91
87
  @host_info = nil
92
- @info = nil
93
88
  @last_error = nil
94
89
  @result_exist = false
95
90
  @local_infile = nil
@@ -106,9 +101,13 @@ class Mysql
106
101
  # flag :: [Integer / nil] connection flag. Mysql::CLIENT_* ORed
107
102
  # === Return
108
103
  # self
109
- def connect(host=nil, user=nil, passwd=nil, db=nil, port=nil, socket=nil, flag=nil)
104
+ def connect(host=nil, user=nil, passwd=nil, db=nil, port=nil, socket=nil, flag=0)
105
+ if flag & CLIENT_COMPRESS != 0
106
+ warn 'unsupported flag: CLIENT_COMPRESS'
107
+ flag &= ~CLIENT_COMPRESS
108
+ end
110
109
  @protocol = Protocol.new host, port, socket, @connect_timeout, @read_timeout, @write_timeout
111
- @protocol.authenticate user, passwd, db, (@local_infile ? CLIENT_LOCAL_FILES : 0) | (flag || 0), @charset
110
+ @protocol.authenticate user, passwd, db, (@local_infile ? CLIENT_LOCAL_FILES : 0) | flag, @charset
112
111
  @charset ||= @protocol.charset
113
112
  @host_info = (host.nil? || host == "localhost") ? 'Localhost via UNIX socket' : "#{host} via TCP/IP"
114
113
  query @init_command if @init_command
@@ -283,13 +282,25 @@ class Mysql
283
282
  # === Return
284
283
  # [String] information for last query
285
284
  def info
286
- @info
285
+ @protocol && @protocol.message
286
+ end
287
+
288
+ # === Return
289
+ # [Integer] number of affected records by insert/update/delete.
290
+ def affected_rows
291
+ @protocol ? @protocol.affected_rows : 0
287
292
  end
288
293
 
289
294
  # === Return
290
295
  # [Integer] latest auto_increment value
291
296
  def insert_id
292
- @insert_id
297
+ @protocol ? @protocol.insert_id : 0
298
+ end
299
+
300
+ # === Return
301
+ # [Integer] number of warnings for previous query
302
+ def warning_count
303
+ @protocol ? @protocol.warning_count : 0
293
304
  end
294
305
 
295
306
  # Kill query.
@@ -333,9 +344,6 @@ class Mysql
333
344
  if nfields
334
345
  @fields = @protocol.retr_fields nfields
335
346
  @result_exist = true
336
- else
337
- @affected_rows, @insert_id, @server_status, @warning_count, @info =
338
- @protocol.affected_rows, @protocol.insert_id, @protocol.server_status, @protocol.warning_count, @protocol.message
339
347
  end
340
348
  if block
341
349
  while true
@@ -364,7 +372,6 @@ class Mysql
364
372
  check_connection
365
373
  raise ClientError, 'invalid usage' unless @result_exist
366
374
  res = Result.new @fields, @protocol
367
- @server_status = @protocol.server_status
368
375
  @result_exist = false
369
376
  res
370
377
  end
@@ -395,7 +402,7 @@ class Mysql
395
402
 
396
403
  # true if multiple queries are specified and unexecuted queries exists.
397
404
  def more_results
398
- @server_status & SERVER_MORE_RESULTS_EXISTS != 0
405
+ @protocol.server_status & SERVER_MORE_RESULTS_EXISTS != 0
399
406
  end
400
407
  alias more_results? more_results
401
408
 
@@ -634,6 +641,7 @@ class Mysql
634
641
  @records = [] # all records
635
642
  @index = 0 # index of record
636
643
  @fieldname_with_table = nil
644
+ @fetched_record = nil
637
645
  end
638
646
 
639
647
  # ignore
@@ -839,6 +847,7 @@ class Mysql
839
847
  @affected_rows = @insert_id = @server_status = @warning_count = 0
840
848
  @sqlstate = "00000"
841
849
  @param_count = nil
850
+ @bind_result = nil
842
851
  end
843
852
 
844
853
  # parse prepared-statement and return Mysql::Statement object
data/lib/mysql/charset.rb CHANGED
@@ -181,6 +181,8 @@ class Mysql
181
181
  CHARSET_DEFAULT[csname] = cs if default
182
182
  end
183
183
 
184
+ BINARY_CHARSET_NUMBER = CHARSET_DEFAULT['binary'].number
185
+
184
186
  def self.by_number(n)
185
187
  raise ClientError, "unknown charset number: #{n}" unless NUMBER_TO_CHARSET.key? n
186
188
  NUMBER_TO_CHARSET[n]
data/lib/mysql/error.rb CHANGED
@@ -744,7 +744,7 @@ class Mysql
744
744
  ER_ERROR_LAST = 1704
745
745
  end
746
746
 
747
- ServerError.define_error_class /\AER_/
747
+ ServerError.define_error_class(/\AER_/)
748
748
  ServerError::ERROR_MAP.values.each{|v| Mysql.const_set v.name.split(/::/).last, v} # for compatibility
749
749
 
750
750
  # client side error
@@ -813,7 +813,7 @@ class Mysql
813
813
  CR_AUTH_PLUGIN_CANNOT_LOAD = 2059
814
814
  end
815
815
 
816
- ClientError.define_error_class /\ACR_/
816
+ ClientError.define_error_class(/\ACR_/)
817
817
 
818
818
  # protocol error
819
819
  class ProtocolError < ClientError
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2008-2010 TOMITA Masahiro
1
+ # Copyright (C) 2008-2012 TOMITA Masahiro
2
2
  # mailto:tommy@tmtm.org
3
3
 
4
4
  require "socket"
@@ -201,6 +201,8 @@ class Mysql
201
201
  # === Exception
202
202
  # [ClientError] :: connection timeout
203
203
  def initialize(host, port, socket, conn_timeout, read_timeout, write_timeout)
204
+ @insert_id = 0
205
+ @warning_count = 0
204
206
  @gc_stmt_queue = [] # stmt id list which GC destroy.
205
207
  set_state :INIT
206
208
  @read_timeout = read_timeout
@@ -231,6 +233,8 @@ class Mysql
231
233
  # db :: [String / nil] default database name. nil: no default.
232
234
  # flag :: [Integer] client flag
233
235
  # charset :: [Mysql::Charset / nil] charset for connection. nil: use server's charset
236
+ # === Exception
237
+ # ProtocolError :: The old style password is not supported
234
238
  def authenticate(user, passwd, db, flag, charset)
235
239
  check_state :INIT
236
240
  @authinfo = [user, passwd, db, flag, charset]
@@ -249,7 +253,7 @@ class Mysql
249
253
  end
250
254
  netpw = encrypt_password passwd, init_packet.scramble_buff
251
255
  write AuthenticationPacket.serialize(client_flags, 1024**3, @charset.number, user, netpw, db)
252
- read # skip OK packet
256
+ raise ProtocolError, 'The old style password is not supported' if read == "\xfe"
253
257
  set_state :READY
254
258
  end
255
259
 
@@ -510,7 +514,7 @@ class Mysql
510
514
  v = self.class.net2value(data, f.type, unsigned)
511
515
  if v.is_a? Numeric or v.is_a? Mysql::Time
512
516
  v
513
- elsif f.type == Field::TYPE_BIT or f.flags & Field::BINARY_FLAG != 0
517
+ elsif f.type == Field::TYPE_BIT or f.charsetnr == Charset::BINARY_CHARSET_NUMBER
514
518
  Charset.to_binary(v)
515
519
  else
516
520
  Charset.convert_encoding(v, charset.encoding)
@@ -568,7 +572,12 @@ class Mysql
568
572
  len = (len2 << 8) + len1
569
573
  raise ProtocolError, "invalid packet: sequence number mismatch(#{seq} != #{@seq}(expected))" if @seq != seq
570
574
  @seq = (@seq + 1) % 256
571
- ret.concat @sock.sysread(len)
575
+ buf = ''.force_encoding('ASCII-8BIT')
576
+ l = len
577
+ while l > 0
578
+ ret.concat @sock.sysread(l, buf)
579
+ l -= buf.bytesize
580
+ end
572
581
  end
573
582
  rescue EOFError
574
583
  raise ClientError::ServerGoneError, 'The MySQL server has gone away'
@@ -0,0 +1,1679 @@
1
+ # -*- coding: utf-8 -*-
2
+ require "tempfile"
3
+
4
+ $LOAD_PATH.unshift "#{File.dirname __FILE__}/../lib"
5
+
6
+ require "mysql"
7
+
8
+ # MYSQL_USER must have ALL privilege for MYSQL_DATABASE.* and RELOAD privilege for *.*
9
+ MYSQL_SERVER = ENV['MYSQL_SERVER']
10
+ MYSQL_USER = ENV['MYSQL_USER']
11
+ MYSQL_PASSWORD = ENV['MYSQL_PASSWORD']
12
+ MYSQL_DATABASE = ENV['MYSQL_DATABASE'] || "test_for_mysql_ruby"
13
+ MYSQL_PORT = ENV['MYSQL_PORT']
14
+ MYSQL_SOCKET = ENV['MYSQL_SOCKET']
15
+
16
+ describe 'Mysql::VERSION' do
17
+ it 'returns client version' do
18
+ Mysql::VERSION.should == 20904
19
+ end
20
+ end
21
+
22
+ describe 'Mysql.init' do
23
+ it 'returns Mysql object' do
24
+ Mysql.init.should be_kind_of Mysql
25
+ end
26
+ end
27
+
28
+ describe 'Mysql.real_connect' do
29
+ it 'connect to mysqld' do
30
+ @m = Mysql.real_connect(MYSQL_SERVER, MYSQL_USER, MYSQL_PASSWORD, MYSQL_DATABASE, MYSQL_PORT, MYSQL_SOCKET)
31
+ @m.should be_kind_of Mysql
32
+ end
33
+ it 'flag argument affects' do
34
+ @m = Mysql.real_connect(MYSQL_SERVER, MYSQL_USER, MYSQL_PASSWORD, MYSQL_DATABASE, MYSQL_PORT, MYSQL_SOCKET, Mysql::CLIENT_FOUND_ROWS)
35
+ @m.query 'create temporary table t (c int)'
36
+ @m.query 'insert into t values (123)'
37
+ @m.query 'update t set c=123'
38
+ @m.affected_rows.should == 1
39
+ end
40
+ after do
41
+ @m.close
42
+ end
43
+ end
44
+
45
+ describe 'Mysql.connect' do
46
+ it 'connect to mysqld' do
47
+ @m = Mysql.connect(MYSQL_SERVER, MYSQL_USER, MYSQL_PASSWORD, MYSQL_DATABASE, MYSQL_PORT, MYSQL_SOCKET)
48
+ @m.should be_kind_of Mysql
49
+ end
50
+ after do
51
+ @m.close if @m
52
+ end
53
+ end
54
+
55
+ describe 'Mysql.new' do
56
+ it 'connect to mysqld' do
57
+ @m = Mysql.new(MYSQL_SERVER, MYSQL_USER, MYSQL_PASSWORD, MYSQL_DATABASE, MYSQL_PORT, MYSQL_SOCKET)
58
+ @m.should be_kind_of Mysql
59
+ end
60
+ after do
61
+ @m.close if @m
62
+ end
63
+ end
64
+
65
+ describe 'Mysql.escape_string' do
66
+ it 'escape special character' do
67
+ Mysql.escape_string("abc'def\"ghi\0jkl%mno").should == "abc\\'def\\\"ghi\\0jkl%mno"
68
+ end
69
+ end
70
+
71
+ describe 'Mysql.quote' do
72
+ it 'escape special character' do
73
+ Mysql.quote("abc'def\"ghi\0jkl%mno").should == "abc\\'def\\\"ghi\\0jkl%mno"
74
+ end
75
+ end
76
+
77
+ describe 'Mysql.client_info' do
78
+ it 'returns client version as string' do
79
+ Mysql.client_info.should == '5.0.0'
80
+ end
81
+ end
82
+
83
+ describe 'Mysql.get_client_info' do
84
+ it 'returns client version as string' do
85
+ Mysql.get_client_info.should == '5.0.0'
86
+ end
87
+ end
88
+
89
+ describe 'Mysql.client_version' do
90
+ it 'returns client version as Integer' do
91
+ Mysql.client_version.should == 50000
92
+ end
93
+ end
94
+
95
+ describe 'Mysql.get_client_version' do
96
+ it 'returns client version as Integer' do
97
+ Mysql.client_version.should == 50000
98
+ end
99
+ end
100
+
101
+ describe 'Mysql#real_connect' do
102
+ it 'connect to mysqld' do
103
+ @m = Mysql.init
104
+ @m.real_connect(MYSQL_SERVER, MYSQL_USER, MYSQL_PASSWORD, MYSQL_DATABASE, MYSQL_PORT, MYSQL_SOCKET).should == @m
105
+ end
106
+ after do
107
+ @m.close if @m
108
+ end
109
+ end
110
+
111
+ describe 'Mysql#connect' do
112
+ it 'connect to mysqld' do
113
+ @m = Mysql.init
114
+ @m.connect(MYSQL_SERVER, MYSQL_USER, MYSQL_PASSWORD, MYSQL_DATABASE, MYSQL_PORT, MYSQL_SOCKET).should == @m
115
+ end
116
+ after do
117
+ @m.close if @m
118
+ end
119
+ end
120
+
121
+ describe 'Mysql#options' do
122
+ before do
123
+ @m = Mysql.init
124
+ end
125
+ after do
126
+ @m.close
127
+ end
128
+ it 'INIT_COMMAND: execute query when connecting' do
129
+ @m.options(Mysql::INIT_COMMAND, "SET AUTOCOMMIT=0").should == @m
130
+ @m.connect(MYSQL_SERVER, MYSQL_USER, MYSQL_PASSWORD, MYSQL_DATABASE, MYSQL_PORT, MYSQL_SOCKET).should == @m
131
+ @m.query('select @@AUTOCOMMIT').fetch_row.should == ["0"]
132
+ end
133
+ it 'OPT_CONNECT_TIMEOUT: set timeout for connecting' do
134
+ @m.options(Mysql::OPT_CONNECT_TIMEOUT, 0.1).should == @m
135
+ UNIXSocket.stub!(:new).and_return{sleep 1}
136
+ TCPSocket.stub!(:new).and_return{sleep 1}
137
+ proc{@m.connect(MYSQL_SERVER, MYSQL_USER, MYSQL_PASSWORD, MYSQL_DATABASE, MYSQL_PORT, MYSQL_SOCKET)}.should raise_error Mysql::ClientError, 'connection timeout'
138
+ proc{@m.connect}.should raise_error Mysql::ClientError, 'connection timeout'
139
+ end
140
+ it 'OPT_LOCAL_INFILE: client can execute LOAD DATA LOCAL INFILE query' do
141
+ tmpf = Tempfile.new 'mysql_spec'
142
+ tmpf.puts "123\tabc\n"
143
+ tmpf.close
144
+ @m.options(Mysql::OPT_LOCAL_INFILE, true).should == @m
145
+ @m.connect(MYSQL_SERVER, MYSQL_USER, MYSQL_PASSWORD, MYSQL_DATABASE, MYSQL_PORT, MYSQL_SOCKET)
146
+ @m.query('create temporary table t (i int, c char(10))')
147
+ @m.query("load data local infile '#{tmpf.path}' into table t")
148
+ @m.query('select * from t').fetch_row.should == ['123','abc']
149
+ end
150
+ it 'OPT_READ_TIMEOUT: set timeout for reading packet' do
151
+ @m.options(Mysql::OPT_READ_TIMEOUT, 10).should == @m
152
+ end
153
+ it 'OPT_WRITE_TIMEOUT: set timeout for writing packet' do
154
+ @m.options(Mysql::OPT_WRITE_TIMEOUT, 10).should == @m
155
+ end
156
+ it 'SET_CHARSET_NAME: set charset for connection' do
157
+ @m.options(Mysql::SET_CHARSET_NAME, 'utf8').should == @m
158
+ @m.connect(MYSQL_SERVER, MYSQL_USER, MYSQL_PASSWORD, MYSQL_DATABASE, MYSQL_PORT, MYSQL_SOCKET)
159
+ @m.query('select @@character_set_connection').fetch_row.should == ['utf8']
160
+ end
161
+ end
162
+
163
+ describe 'Mysql' do
164
+ before do
165
+ @m = Mysql.new(MYSQL_SERVER, MYSQL_USER, MYSQL_PASSWORD, MYSQL_DATABASE, MYSQL_PORT, MYSQL_SOCKET)
166
+ end
167
+
168
+ after do
169
+ @m.close if @m rescue nil
170
+ end
171
+
172
+ describe '#escape_string' do
173
+ if defined? ::Encoding
174
+ it 'escape special character for charset' do
175
+ @m.charset = 'cp932'
176
+ @m.escape_string("abc'def\"ghi\0jkl%mno_表".encode('cp932')).should == "abc\\'def\\\"ghi\\0jkl%mno_表".encode('cp932')
177
+ end
178
+ else
179
+ it 'raise error if charset is multibyte' do
180
+ @m.charset = 'cp932'
181
+ proc{@m.escape_string("abc'def\"ghi\0jkl%mno_\x95\\")}.should raise_error(Mysql::ClientError, 'Mysql#escape_string is called for unsafe multibyte charset')
182
+ end
183
+ it 'not warn if charset is singlebyte' do
184
+ @m.charset = 'latin1'
185
+ @m.escape_string("abc'def\"ghi\0jkl%mno_\x95\\").should == "abc\\'def\\\"ghi\\0jkl%mno_\x95\\\\"
186
+ end
187
+ end
188
+ end
189
+
190
+ describe '#quote' do
191
+ it 'is alias of #escape_string' do
192
+ @m.method(:quote).should == @m.method(:escape_string)
193
+ end
194
+ end
195
+
196
+ describe '#client_info' do
197
+ it 'returns client version as string' do
198
+ @m.client_info.should == '5.0.0'
199
+ end
200
+ end
201
+
202
+ describe '#get_client_info' do
203
+ it 'returns client version as string' do
204
+ @m.get_client_info.should == '5.0.0'
205
+ end
206
+ end
207
+
208
+ describe '#affected_rows' do
209
+ it 'returns number of affected rows' do
210
+ @m.query 'create temporary table t (id int)'
211
+ @m.query 'insert into t values (1),(2)'
212
+ @m.affected_rows.should == 2
213
+ end
214
+ end
215
+
216
+ describe '#character_set_name' do
217
+ it 'returns charset name' do
218
+ m = Mysql.init
219
+ m.options Mysql::SET_CHARSET_NAME, 'cp932'
220
+ m.connect MYSQL_SERVER, MYSQL_USER, MYSQL_PASSWORD, MYSQL_DATABASE, MYSQL_PORT, MYSQL_SOCKET
221
+ m.character_set_name.should == 'cp932'
222
+ end
223
+ end
224
+
225
+ describe '#close' do
226
+ it 'returns self' do
227
+ @m.close.should == @m
228
+ end
229
+ end
230
+
231
+ describe '#close!' do
232
+ it 'returns self' do
233
+ @m.close!.should == @m
234
+ end
235
+ end
236
+
237
+ # describe '#create_db' do
238
+ # end
239
+
240
+ # describe '#drop_db' do
241
+ # end
242
+
243
+ describe '#errno' do
244
+ it 'default value is 0' do
245
+ @m.errno.should == 0
246
+ end
247
+ it 'returns error number of latest error' do
248
+ @m.query('hogehoge') rescue nil
249
+ @m.errno.should == 1064
250
+ end
251
+ end
252
+
253
+ describe '#error' do
254
+ it 'returns error message of latest error' do
255
+ @m.query('hogehoge') rescue nil
256
+ @m.error.should == "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'hogehoge' at line 1"
257
+ end
258
+ end
259
+
260
+ describe '#field_count' do
261
+ it 'returns number of fields for latest query' do
262
+ @m.query 'select 1,2,3'
263
+ @m.field_count.should == 3
264
+ end
265
+ end
266
+
267
+ describe '#client_version' do
268
+ it 'returns client version as Integer' do
269
+ @m.client_version.should be_kind_of Integer
270
+ end
271
+ end
272
+
273
+ describe '#get_client_version' do
274
+ it 'returns client version as Integer' do
275
+ @m.get_client_version.should be_kind_of Integer
276
+ end
277
+ end
278
+
279
+ describe '#get_host_info' do
280
+ it 'returns connection type as String' do
281
+ if MYSQL_SERVER == nil or MYSQL_SERVER == 'localhost'
282
+ @m.get_host_info.should == 'Localhost via UNIX socket'
283
+ else
284
+ @m.get_host_info.should == "#{MYSQL_SERVER} via TCP/IP"
285
+ end
286
+ end
287
+ end
288
+
289
+ describe '#host_info' do
290
+ it 'returns connection type as String' do
291
+ if MYSQL_SERVER == nil or MYSQL_SERVER == 'localhost'
292
+ @m.host_info.should == 'Localhost via UNIX socket'
293
+ else
294
+ @m.host_info.should == "#{MYSQL_SERVER} via TCP/IP"
295
+ end
296
+ end
297
+ end
298
+
299
+ describe '#get_proto_info' do
300
+ it 'returns version of connection as Integer' do
301
+ @m.get_proto_info.should == 10
302
+ end
303
+ end
304
+
305
+ describe '#proto_info' do
306
+ it 'returns version of connection as Integer' do
307
+ @m.proto_info.should == 10
308
+ end
309
+ end
310
+
311
+ describe '#get_server_info' do
312
+ it 'returns server version as String' do
313
+ @m.get_server_info.should =~ /\A\d+\.\d+\.\d+/
314
+ end
315
+ end
316
+
317
+ describe '#server_info' do
318
+ it 'returns server version as String' do
319
+ @m.server_info.should =~ /\A\d+\.\d+\.\d+/
320
+ end
321
+ end
322
+
323
+ describe '#info' do
324
+ it 'returns information of latest query' do
325
+ @m.query 'create temporary table t (id int)'
326
+ @m.query 'insert into t values (1),(2),(3)'
327
+ @m.info.should == 'Records: 3 Duplicates: 0 Warnings: 0'
328
+ end
329
+ end
330
+
331
+ describe '#insert_id' do
332
+ it 'returns latest auto_increment value' do
333
+ @m.query 'create temporary table t (id int auto_increment, unique (id))'
334
+ @m.query 'insert into t values (0)'
335
+ @m.insert_id.should == 1
336
+ @m.query 'alter table t auto_increment=1234'
337
+ @m.query 'insert into t values (0)'
338
+ @m.insert_id.should == 1234
339
+ end
340
+ end
341
+
342
+ describe '#kill' do
343
+ it 'returns self' do
344
+ @m.kill(@m.thread_id).should == @m
345
+ end
346
+ it 'kill specified connection' do
347
+ m = Mysql.new(MYSQL_SERVER, MYSQL_USER, MYSQL_PASSWORD, MYSQL_DATABASE, MYSQL_PORT, MYSQL_SOCKET)
348
+ m.list_processes.map(&:first).should be_include @m.thread_id.to_s
349
+ m.close
350
+ end
351
+ end
352
+
353
+ describe '#list_dbs' do
354
+ it 'returns database list' do
355
+ ret = @m.list_dbs
356
+ ret.should be_kind_of Array
357
+ ret.should be_include MYSQL_DATABASE
358
+ end
359
+ it 'with pattern returns databases that matches pattern' do
360
+ @m.list_dbs('info%').should be_include 'information_schema'
361
+ end
362
+ end
363
+
364
+ describe '#list_fields' do
365
+ before do
366
+ @m.query 'create temporary table t (i int, c char(10), d date)'
367
+ end
368
+ it 'returns result set that contains information of fields' do
369
+ ret = @m.list_fields('t')
370
+ ret.should be_kind_of Mysql::Result
371
+ ret.num_rows.should == 0
372
+ ret.fetch_fields.map{|f|f.name}.should == ['i','c','d']
373
+ end
374
+ it 'with pattern returns result set that contains information of fields that matches pattern' do
375
+ ret = @m.list_fields('t', 'i')
376
+ ret.should be_kind_of Mysql::Result
377
+ ret.num_rows.should == 0
378
+ ret.fetch_fields.map{|f|f.name}.should == ['i']
379
+ end
380
+ end
381
+
382
+ describe '#list_processes' do
383
+ it 'returns result set that contains information of all connections' do
384
+ ret = @m.list_processes
385
+ ret.should be_kind_of Mysql::Result
386
+ ret.find{|r|r[0].to_i == @m.thread_id}[4].should == "Processlist"
387
+ end
388
+ end
389
+
390
+ describe '#list_tables' do
391
+ before do
392
+ @m.query 'create table test_mysql_list_tables (id int)'
393
+ end
394
+ after do
395
+ @m.query 'drop table test_mysql_list_tables'
396
+ end
397
+ it 'returns table list' do
398
+ ret = @m.list_tables
399
+ ret.should be_kind_of Array
400
+ ret.should be_include 'test_mysql_list_tables'
401
+ end
402
+ it 'with pattern returns lists that matches pattern' do
403
+ ret = @m.list_tables '%mysql\_list\_t%'
404
+ ret.should be_include 'test_mysql_list_tables'
405
+ end
406
+ end
407
+
408
+ describe '#ping' do
409
+ it 'returns self' do
410
+ @m.ping.should == @m
411
+ end
412
+ end
413
+
414
+ describe '#query' do
415
+ it 'returns Mysql::Result if query returns results' do
416
+ @m.query('select 123').should be_kind_of Mysql::Result
417
+ end
418
+ it 'returns nil if query returns no results' do
419
+ @m.query('set @hoge:=123').should == nil
420
+ end
421
+ it 'returns self if query_with_result is false' do
422
+ @m.query_with_result = false
423
+ @m.query('select 123').should == @m
424
+ @m.store_result
425
+ @m.query('set @hoge:=123').should == @m
426
+ end
427
+ end
428
+
429
+ describe '#real_query' do
430
+ it 'is same as #query' do
431
+ @m.real_query('select 123').should be_kind_of Mysql::Result
432
+ end
433
+ end
434
+
435
+ describe '#refresh' do
436
+ it 'returns self' do
437
+ @m.refresh(Mysql::REFRESH_HOSTS).should == @m
438
+ end
439
+ end
440
+
441
+ describe '#reload' do
442
+ it 'returns self' do
443
+ @m.reload.should == @m
444
+ end
445
+ end
446
+
447
+ describe '#select_db' do
448
+ it 'changes default database' do
449
+ @m.select_db 'information_schema'
450
+ @m.query('select database()').fetch_row.first.should == 'information_schema'
451
+ end
452
+ end
453
+
454
+ # describe '#shutdown' do
455
+ # end
456
+
457
+ describe '#stat' do
458
+ it 'returns server status' do
459
+ @m.stat.should =~ /\AUptime: \d+ Threads: \d+ Questions: \d+ Slow queries: \d+ Opens: \d+ Flush tables: \d+ Open tables: \d+ Queries per second avg: \d+\.\d+\z/
460
+ end
461
+ end
462
+
463
+ describe '#store_result' do
464
+ it 'returns Mysql::Result' do
465
+ @m.query_with_result = false
466
+ @m.query 'select 1,2,3'
467
+ ret = @m.store_result
468
+ ret.should be_kind_of Mysql::Result
469
+ ret.fetch_row.should == ['1','2','3']
470
+ end
471
+ it 'raises error when no query' do
472
+ proc{@m.store_result}.should raise_error Mysql::Error
473
+ end
474
+ it 'raises error when query does not return results' do
475
+ @m.query 'set @hoge:=123'
476
+ proc{@m.store_result}.should raise_error Mysql::Error
477
+ end
478
+ end
479
+
480
+ describe '#thread_id' do
481
+ it 'returns thread id as Integer' do
482
+ @m.thread_id.should be_kind_of Integer
483
+ end
484
+ end
485
+
486
+ describe '#use_result' do
487
+ it 'returns Mysql::Result' do
488
+ @m.query_with_result = false
489
+ @m.query 'select 1,2,3'
490
+ ret = @m.use_result
491
+ ret.should be_kind_of Mysql::Result
492
+ ret.fetch_row.should == ['1','2','3']
493
+ end
494
+ it 'raises error when no query' do
495
+ proc{@m.use_result}.should raise_error Mysql::Error
496
+ end
497
+ it 'raises error when query does not return results' do
498
+ @m.query 'set @hoge:=123'
499
+ proc{@m.use_result}.should raise_error Mysql::Error
500
+ end
501
+ end
502
+
503
+ describe '#get_server_version' do
504
+ it 'returns server version as Integer' do
505
+ @m.get_server_version.should be_kind_of Integer
506
+ end
507
+ end
508
+
509
+ describe '#server_version' do
510
+ it 'returns server version as Integer' do
511
+ @m.server_version.should be_kind_of Integer
512
+ end
513
+ end
514
+
515
+ describe '#warning_count' do
516
+ it 'default values is zero' do
517
+ @m.warning_count.should == 0
518
+ end
519
+ it 'returns number of warnings' do
520
+ @m.query 'create temporary table t (i tinyint)'
521
+ @m.query 'insert into t values (1234567)'
522
+ @m.warning_count.should == 1
523
+ end
524
+ end
525
+
526
+ describe '#commit' do
527
+ it 'returns self' do
528
+ @m.commit.should == @m
529
+ end
530
+ end
531
+
532
+ describe '#rollback' do
533
+ it 'returns self' do
534
+ @m.rollback.should == @m
535
+ end
536
+ end
537
+
538
+ describe '#autocommit' do
539
+ it 'returns self' do
540
+ @m.autocommit(true).should == @m
541
+ end
542
+
543
+ it 'change auto-commit mode' do
544
+ @m.autocommit(true)
545
+ @m.query('select @@autocommit').fetch_row.should == ['1']
546
+ @m.autocommit(false)
547
+ @m.query('select @@autocommit').fetch_row.should == ['0']
548
+ end
549
+ end
550
+
551
+ describe '#set_server_option' do
552
+ it 'returns self' do
553
+ @m.set_server_option(Mysql::OPTION_MULTI_STATEMENTS_ON).should == @m
554
+ end
555
+ end
556
+
557
+ describe '#sqlstate' do
558
+ it 'default values is "00000"' do
559
+ @m.sqlstate.should == "00000"
560
+ end
561
+ it 'returns sqlstate code' do
562
+ proc{@m.query("hoge")}.should raise_error
563
+ @m.sqlstate.should == "42000"
564
+ end
565
+ end
566
+
567
+ describe '#query_with_result' do
568
+ it 'default value is true' do
569
+ @m.query_with_result.should == true
570
+ end
571
+ it 'can set value' do
572
+ (@m.query_with_result=true).should == true
573
+ @m.query_with_result.should == true
574
+ (@m.query_with_result=false).should == false
575
+ @m.query_with_result.should == false
576
+ end
577
+ end
578
+
579
+ describe '#query_with_result is false' do
580
+ it 'Mysql#query returns self and Mysql#store_result returns result set' do
581
+ @m.query_with_result = false
582
+ @m.query('select 1,2,3').should == @m
583
+ res = @m.store_result
584
+ res.fetch_row.should == ['1','2','3']
585
+ end
586
+ end
587
+
588
+ describe '#query with block' do
589
+ it 'returns self' do
590
+ @m.query('select 1'){}.should == @m
591
+ end
592
+ it 'evaluate block with Mysql::Result' do
593
+ @m.query('select 1'){|res| res.should be_kind_of Mysql::Result}.should == @m
594
+ end
595
+ it 'evaluate block multiple times if multiple query is specified' do
596
+ @m.set_server_option Mysql::OPTION_MULTI_STATEMENTS_ON
597
+ cnt = 0
598
+ expect = [["1"], ["2"]]
599
+ @m.query('select 1; select 2'){|res|
600
+ res.fetch_row.should == expect.shift
601
+ cnt += 1
602
+ }.should == @m
603
+ cnt.should == 2
604
+ end
605
+ it 'evaluate block only when query has result' do
606
+ @m.set_server_option Mysql::OPTION_MULTI_STATEMENTS_ON
607
+ cnt = 0
608
+ expect = [["1"], ["2"]]
609
+ @m.query('select 1; set @hoge:=1; select 2'){|res|
610
+ res.fetch_row.should == expect.shift
611
+ cnt += 1
612
+ }.should == @m
613
+ cnt.should == 2
614
+ end
615
+ end
616
+ end
617
+
618
+ describe 'multiple statement query:' do
619
+ before :all do
620
+ @m = Mysql.new(MYSQL_SERVER, MYSQL_USER, MYSQL_PASSWORD, MYSQL_DATABASE, MYSQL_PORT, MYSQL_SOCKET)
621
+ @m.set_server_option(Mysql::OPTION_MULTI_STATEMENTS_ON)
622
+ @res = @m.query 'select 1,2; select 3,4,5'
623
+ end
624
+ it 'Mysql#query returns results for first query' do
625
+ @res.entries.should == [['1','2']]
626
+ end
627
+ it 'Mysql#more_results is true' do
628
+ @m.more_results.should == true
629
+ end
630
+ it 'Mysql#more_results? is true' do
631
+ @m.more_results?.should == true
632
+ end
633
+ it 'Mysql#next_result is true' do
634
+ @m.next_result.should == true
635
+ end
636
+ it 'Mysql#store_result returns results for next query' do
637
+ res = @m.store_result
638
+ res.entries.should == [['3','4','5']]
639
+ end
640
+ it 'Mysql#more_results is false' do
641
+ @m.more_results.should == false
642
+ end
643
+ it 'Mysql#more_results? is false' do
644
+ @m.more_results?.should == false
645
+ end
646
+ it 'Mysql#next_result is false' do
647
+ @m.next_result.should == false
648
+ end
649
+ end
650
+
651
+ describe 'Mysql::Result' do
652
+ before do
653
+ @m = Mysql.new(MYSQL_SERVER, MYSQL_USER, MYSQL_PASSWORD, MYSQL_DATABASE, MYSQL_PORT, MYSQL_SOCKET)
654
+ @m.query 'create temporary table t (id int, str char(10), primary key (id))'
655
+ @m.query "insert into t values (1,'abc'),(2,'defg'),(3,'hi'),(4,null)"
656
+ @res = @m.query 'select * from t'
657
+ end
658
+
659
+ after do
660
+ @m.close if @m
661
+ end
662
+
663
+ it '#data_seek set position of current record' do
664
+ @res.fetch_row.should == ['1', 'abc']
665
+ @res.fetch_row.should == ['2', 'defg']
666
+ @res.fetch_row.should == ['3', 'hi']
667
+ @res.data_seek 1
668
+ @res.fetch_row.should == ['2', 'defg']
669
+ end
670
+
671
+ it '#fetch_field return current field' do
672
+ f = @res.fetch_field
673
+ f.name.should == 'id'
674
+ f.table.should == 't'
675
+ f.def.should == nil
676
+ f.type.should == Mysql::Field::TYPE_LONG
677
+ f.length.should == 11
678
+ f.max_length == 1
679
+ f.flags.should == Mysql::Field::NUM_FLAG|Mysql::Field::PRI_KEY_FLAG|Mysql::Field::PART_KEY_FLAG|Mysql::Field::NOT_NULL_FLAG
680
+ f.decimals.should == 0
681
+
682
+ f = @res.fetch_field
683
+ f.name.should == 'str'
684
+ f.table.should == 't'
685
+ f.def.should == nil
686
+ f.type.should == Mysql::Field::TYPE_STRING
687
+ f.length.should == 10
688
+ f.max_length == 4
689
+ f.flags.should == 0
690
+ f.decimals.should == 0
691
+
692
+ @res.fetch_field.should == nil
693
+ end
694
+
695
+ it '#fetch_fields returns array of fields' do
696
+ ret = @res.fetch_fields
697
+ ret.size.should == 2
698
+ ret[0].name.should == 'id'
699
+ ret[1].name.should == 'str'
700
+ end
701
+
702
+ it '#fetch_field_direct returns field' do
703
+ f = @res.fetch_field_direct 0
704
+ f.name.should == 'id'
705
+ f = @res.fetch_field_direct 1
706
+ f.name.should == 'str'
707
+ proc{@res.fetch_field_direct(-1)}.should raise_error Mysql::ClientError, 'invalid argument: -1'
708
+ proc{@res.fetch_field_direct 2}.should raise_error Mysql::ClientError, 'invalid argument: 2'
709
+ end
710
+
711
+ it '#fetch_lengths returns array of length of field data' do
712
+ @res.fetch_lengths.should == nil
713
+ @res.fetch_row
714
+ @res.fetch_lengths.should == [1, 3]
715
+ @res.fetch_row
716
+ @res.fetch_lengths.should == [1, 4]
717
+ @res.fetch_row
718
+ @res.fetch_lengths.should == [1, 2]
719
+ @res.fetch_row
720
+ @res.fetch_lengths.should == [1, 0]
721
+ @res.fetch_row
722
+ @res.fetch_lengths.should == nil
723
+ end
724
+
725
+ it '#fetch_row returns one record as array for current record' do
726
+ @res.fetch_row.should == ['1', 'abc']
727
+ @res.fetch_row.should == ['2', 'defg']
728
+ @res.fetch_row.should == ['3', 'hi']
729
+ @res.fetch_row.should == ['4', nil]
730
+ @res.fetch_row.should == nil
731
+ end
732
+
733
+ it '#fetch_hash returns one record as hash for current record' do
734
+ @res.fetch_hash.should == {'id'=>'1', 'str'=>'abc'}
735
+ @res.fetch_hash.should == {'id'=>'2', 'str'=>'defg'}
736
+ @res.fetch_hash.should == {'id'=>'3', 'str'=>'hi'}
737
+ @res.fetch_hash.should == {'id'=>'4', 'str'=>nil}
738
+ @res.fetch_hash.should == nil
739
+ end
740
+
741
+ it '#fetch_hash(true) returns with table name' do
742
+ @res.fetch_hash(true).should == {'t.id'=>'1', 't.str'=>'abc'}
743
+ @res.fetch_hash(true).should == {'t.id'=>'2', 't.str'=>'defg'}
744
+ @res.fetch_hash(true).should == {'t.id'=>'3', 't.str'=>'hi'}
745
+ @res.fetch_hash(true).should == {'t.id'=>'4', 't.str'=>nil}
746
+ @res.fetch_hash(true).should == nil
747
+ end
748
+
749
+ it '#num_fields returns number of fields' do
750
+ @res.num_fields.should == 2
751
+ end
752
+
753
+ it '#num_rows returns number of records' do
754
+ @res.num_rows.should == 4
755
+ end
756
+
757
+ it '#each iterate block with a record' do
758
+ expect = [["1","abc"], ["2","defg"], ["3","hi"], ["4",nil]]
759
+ @res.each do |a|
760
+ a.should == expect.shift
761
+ end
762
+ end
763
+
764
+ it '#each_hash iterate block with a hash' do
765
+ expect = [{"id"=>"1","str"=>"abc"}, {"id"=>"2","str"=>"defg"}, {"id"=>"3","str"=>"hi"}, {"id"=>"4","str"=>nil}]
766
+ @res.each_hash do |a|
767
+ a.should == expect.shift
768
+ end
769
+ end
770
+
771
+ it '#each_hash(true): hash key has table name' do
772
+ expect = [{"t.id"=>"1","t.str"=>"abc"}, {"t.id"=>"2","t.str"=>"defg"}, {"t.id"=>"3","t.str"=>"hi"}, {"t.id"=>"4","t.str"=>nil}]
773
+ @res.each_hash(true) do |a|
774
+ a.should == expect.shift
775
+ end
776
+ end
777
+
778
+ it '#row_tell returns position of current record, #row_seek set position of current record' do
779
+ @res.fetch_row.should == ['1', 'abc']
780
+ pos = @res.row_tell
781
+ @res.fetch_row.should == ['2', 'defg']
782
+ @res.fetch_row.should == ['3', 'hi']
783
+ @res.row_seek pos
784
+ @res.fetch_row.should == ['2', 'defg']
785
+ end
786
+
787
+ it '#field_tell returns position of current field, #field_seek set position of current field' do
788
+ @res.field_tell.should == 0
789
+ @res.fetch_field
790
+ @res.field_tell.should == 1
791
+ @res.fetch_field
792
+ @res.field_tell.should == 2
793
+ @res.field_seek 1
794
+ @res.field_tell.should == 1
795
+ end
796
+
797
+ it '#free returns nil' do
798
+ @res.free.should == nil
799
+ end
800
+
801
+ it '#num_fields returns number of fields' do
802
+ @res.num_fields.should == 2
803
+ end
804
+
805
+ it '#num_rows returns number of records' do
806
+ @res.num_rows.should == 4
807
+ end
808
+ end
809
+
810
+ describe 'Mysql::Field' do
811
+ before do
812
+ @m = Mysql.new(MYSQL_SERVER, MYSQL_USER, MYSQL_PASSWORD, MYSQL_DATABASE, MYSQL_PORT, MYSQL_SOCKET)
813
+ @m.query 'create temporary table t (id int default 0, str char(10), primary key (id))'
814
+ @m.query "insert into t values (1,'abc'),(2,'defg'),(3,'hi'),(4,null)"
815
+ @res = @m.query 'select * from t'
816
+ end
817
+
818
+ after do
819
+ @m.close if @m
820
+ end
821
+
822
+ it '#name is name of field' do
823
+ @res.fetch_field.name.should == 'id'
824
+ end
825
+
826
+ it '#table is name of table for field' do
827
+ @res.fetch_field.table.should == 't'
828
+ end
829
+
830
+ it '#def for result set is null' do
831
+ @res.fetch_field.def.should == nil
832
+ end
833
+
834
+ it '#def for field information is default value' do
835
+ @m.list_fields('t').fetch_field.def.should == '0'
836
+ end
837
+
838
+ it '#type is type of field as Integer' do
839
+ @res.fetch_field.type.should == Mysql::Field::TYPE_LONG
840
+ @res.fetch_field.type.should == Mysql::Field::TYPE_STRING
841
+ end
842
+
843
+ it '#length is length of field' do
844
+ @res.fetch_field.length.should == 11
845
+ @res.fetch_field.length.should == 10
846
+ end
847
+
848
+ it '#max_length is maximum length of field value' do
849
+ @res.fetch_field.max_length.should == 1
850
+ @res.fetch_field.max_length.should == 4
851
+ end
852
+
853
+ it '#flags is flag of field as Integer' do
854
+ @res.fetch_field.flags.should == Mysql::Field::NUM_FLAG|Mysql::Field::PRI_KEY_FLAG|Mysql::Field::PART_KEY_FLAG|Mysql::Field::NOT_NULL_FLAG
855
+ @res.fetch_field.flags.should == 0
856
+ end
857
+
858
+ it '#decimals is number of decimal digits' do
859
+ @m.query('select 1.23').fetch_field.decimals.should == 2
860
+ end
861
+
862
+ it '#hash return field as hash' do
863
+ @res.fetch_field.hash.should == {
864
+ 'name' => 'id',
865
+ 'table' => 't',
866
+ 'def' => nil,
867
+ 'type' => Mysql::Field::TYPE_LONG,
868
+ 'length' => 11,
869
+ 'max_length' => 1,
870
+ 'flags' => Mysql::Field::NUM_FLAG|Mysql::Field::PRI_KEY_FLAG|Mysql::Field::PART_KEY_FLAG|Mysql::Field::NOT_NULL_FLAG,
871
+ 'decimals' => 0,
872
+ }
873
+ @res.fetch_field.hash.should == {
874
+ 'name' => 'str',
875
+ 'table' => 't',
876
+ 'def' => nil,
877
+ 'type' => Mysql::Field::TYPE_STRING,
878
+ 'length' => 10,
879
+ 'max_length' => 4,
880
+ 'flags' => 0,
881
+ 'decimals' => 0,
882
+ }
883
+ end
884
+
885
+ it '#inspect returns "#<Mysql::Field:name>"' do
886
+ @res.fetch_field.inspect.should == '#<Mysql::Field:id>'
887
+ @res.fetch_field.inspect.should == '#<Mysql::Field:str>'
888
+ end
889
+
890
+ it '#is_num? returns true if the field is numeric' do
891
+ @res.fetch_field.is_num?.should == true
892
+ @res.fetch_field.is_num?.should == false
893
+ end
894
+
895
+ it '#is_not_null? returns true if the field is not null' do
896
+ @res.fetch_field.is_not_null?.should == true
897
+ @res.fetch_field.is_not_null?.should == false
898
+ end
899
+
900
+ it '#is_pri_key? returns true if the field is primary key' do
901
+ @res.fetch_field.is_pri_key?.should == true
902
+ @res.fetch_field.is_pri_key?.should == false
903
+ end
904
+ end
905
+
906
+ describe 'create Mysql::Stmt object:' do
907
+ before do
908
+ @m = Mysql.new(MYSQL_SERVER, MYSQL_USER, MYSQL_PASSWORD, MYSQL_DATABASE, MYSQL_PORT, MYSQL_SOCKET)
909
+ end
910
+
911
+ after do
912
+ @m.close if @m
913
+ end
914
+
915
+ it 'Mysql#stmt_init returns Mysql::Stmt object' do
916
+ @m.stmt_init.should be_kind_of Mysql::Stmt
917
+ end
918
+
919
+ it 'Mysq;#prepare returns Mysql::Stmt object' do
920
+ @m.prepare("select 1").should be_kind_of Mysql::Stmt
921
+ end
922
+ end
923
+
924
+ describe 'Mysql::Stmt' do
925
+ before do
926
+ @m = Mysql.new(MYSQL_SERVER, MYSQL_USER, MYSQL_PASSWORD, MYSQL_DATABASE, MYSQL_PORT, MYSQL_SOCKET)
927
+ @s = @m.stmt_init
928
+ end
929
+
930
+ after do
931
+ @s.close if @s rescue nil
932
+ @m.close if @m
933
+ end
934
+
935
+ it '#affected_rows returns number of affected records' do
936
+ @m.query 'create temporary table t (i int, c char(10))'
937
+ @s.prepare 'insert into t values (?,?)'
938
+ @s.execute 1, 'hoge'
939
+ @s.affected_rows.should == 1
940
+ @s.execute 2, 'hoge'
941
+ @s.execute 3, 'hoge'
942
+ @s.prepare 'update t set c=?'
943
+ @s.execute 'fuga'
944
+ @s.affected_rows.should == 3
945
+ end
946
+
947
+ describe '#bind_result' do
948
+ before do
949
+ @m.query 'create temporary table t (i int, c char(10), d double, t datetime)'
950
+ @m.query 'insert into t values (123,"9abcdefg",1.2345,20091208100446)'
951
+ @s.prepare 'select * from t'
952
+ end
953
+
954
+ it '(nil) make result format to be standard value' do
955
+ @s.bind_result nil, nil, nil, nil
956
+ @s.execute
957
+ @s.fetch.should == [123, '9abcdefg', 1.2345, Mysql::Time.new(2009,12,8,10,4,46)]
958
+ end
959
+
960
+ it '(Numeric) make result format to be Integer value' do
961
+ @s.bind_result Numeric, Numeric, Numeric, Numeric
962
+ @s.execute
963
+ @s.fetch.should == [123, 9, 1, 20091208100446]
964
+ end
965
+
966
+ it '(Integer) make result format to be Integer value' do
967
+ @s.bind_result Integer, Integer, Integer, Integer
968
+ @s.execute
969
+ @s.fetch.should == [123, 9, 1, 20091208100446]
970
+ end
971
+
972
+ it '(Fixnum) make result format to be Integer value' do
973
+ @s.bind_result Fixnum, Fixnum, Fixnum, Fixnum
974
+ @s.execute
975
+ @s.fetch.should == [123, 9, 1, 20091208100446]
976
+ end
977
+
978
+ it '(String) make result format to be String value' do
979
+ @s.bind_result String, String, String, String
980
+ @s.execute
981
+ @s.fetch.should == ["123", "9abcdefg", "1.2345", "2009-12-08 10:04:46"]
982
+ end
983
+
984
+ it '(Float) make result format to be Float value' do
985
+ @s.bind_result Float, Float, Float, Float
986
+ @s.execute
987
+ @s.fetch.should == [123.0, 9.0, 1.2345 , 20091208100446.0]
988
+ end
989
+
990
+ it '(Mysql::Time) make result format to be Mysql::Time value' do
991
+ @s.bind_result Mysql::Time, Mysql::Time, Mysql::Time, Mysql::Time
992
+ @s.execute
993
+ @s.fetch.should == [Mysql::Time.new(2000,1,23), Mysql::Time.new, Mysql::Time.new, Mysql::Time.new(2009,12,8,10,4,46)]
994
+ end
995
+
996
+ it '(invalid) raises error' do
997
+ proc{@s.bind_result(Time, nil, nil, nil)}.should raise_error(TypeError)
998
+ end
999
+
1000
+ it 'with mismatch argument count raise error' do
1001
+ proc{@s.bind_result(nil)}.should raise_error(Mysql::ClientError, 'bind_result: result value count(4) != number of argument(1)')
1002
+ end
1003
+ end
1004
+
1005
+ it '#close returns nil' do
1006
+ @s.close.should == nil
1007
+ end
1008
+
1009
+ it '#data_seek set position of current record' do
1010
+ @m.query 'create temporary table t (i int)'
1011
+ @m.query 'insert into t values (0),(1),(2),(3),(4),(5),(6)'
1012
+ @s.prepare 'select i from t'
1013
+ @s.execute
1014
+ @s.fetch.should == [0]
1015
+ @s.fetch.should == [1]
1016
+ @s.fetch.should == [2]
1017
+ @s.data_seek 5
1018
+ @s.fetch.should == [5]
1019
+ @s.data_seek 1
1020
+ @s.fetch.should == [1]
1021
+ end
1022
+
1023
+ it '#each iterate block with a record' do
1024
+ @m.query 'create temporary table t (i int, c char(255), d datetime)'
1025
+ @m.query "insert into t values (1,'abc','19701224235905'),(2,'def','21120903123456'),(3,'123',null)"
1026
+ @s.prepare 'select * from t'
1027
+ @s.execute
1028
+ expect = [
1029
+ [1, 'abc', Mysql::Time.new(1970,12,24,23,59,05)],
1030
+ [2, 'def', Mysql::Time.new(2112,9,3,12,34,56)],
1031
+ [3, '123', nil],
1032
+ ]
1033
+ @s.each do |a|
1034
+ a.should == expect.shift
1035
+ end
1036
+ end
1037
+
1038
+ it '#execute returns self' do
1039
+ @s.prepare 'select 1'
1040
+ @s.execute.should == @s
1041
+ end
1042
+
1043
+ it '#execute pass arguments to query' do
1044
+ @m.query 'create temporary table t (i int)'
1045
+ @s.prepare 'insert into t values (?)'
1046
+ @s.execute 123
1047
+ @s.execute '456'
1048
+ @m.query('select * from t').entries.should == [['123'], ['456']]
1049
+ end
1050
+
1051
+ it '#execute with various arguments' do
1052
+ @m.query 'create temporary table t (i int, c char(255), t timestamp)'
1053
+ @s.prepare 'insert into t values (?,?,?)'
1054
+ @s.execute 123, 'hoge', Time.local(2009,12,8,19,56,21)
1055
+ @m.query('select * from t').fetch_row.should == ['123', 'hoge', '2009-12-08 19:56:21']
1056
+ end
1057
+
1058
+ it '#execute with arguments that is invalid count raise error' do
1059
+ @s.prepare 'select ?'
1060
+ proc{@s.execute 123, 456}.should raise_error(Mysql::ClientError, 'parameter count mismatch')
1061
+ end
1062
+
1063
+ it '#execute with huge value' do
1064
+ [30, 31, 32, 62, 63].each do |i|
1065
+ @m.prepare('select cast(? as signed)').execute(2**i-1).fetch.should == [2**i-1]
1066
+ @m.prepare('select cast(? as signed)').execute(-(2**i)).fetch.should == [-2**i]
1067
+ end
1068
+ end
1069
+
1070
+ it '#fetch returns result-record' do
1071
+ @s.prepare 'select 123, "abc", null'
1072
+ @s.execute
1073
+ @s.fetch.should == [123, 'abc', nil]
1074
+ end
1075
+
1076
+ it '#fetch bit column (8bit)' do
1077
+ @m.query 'create temporary table t (i bit(8))'
1078
+ @m.query 'insert into t values (0),(-1),(127),(-128),(255),(-255),(256)'
1079
+ @s.prepare 'select i from t'
1080
+ @s.execute
1081
+ if defined? Encoding
1082
+ @s.entries.should == [
1083
+ ["\x00".force_encoding('ASCII-8BIT')],
1084
+ ["\xff".force_encoding('ASCII-8BIT')],
1085
+ ["\x7f".force_encoding('ASCII-8BIT')],
1086
+ ["\xff".force_encoding('ASCII-8BIT')],
1087
+ ["\xff".force_encoding('ASCII-8BIT')],
1088
+ ["\xff".force_encoding('ASCII-8BIT')],
1089
+ ["\xff".force_encoding('ASCII-8BIT')],
1090
+ ]
1091
+ else
1092
+ @s.entries.should == [["\x00"], ["\xff"], ["\x7f"], ["\xff"], ["\xff"], ["\xff"], ["\xff"]]
1093
+ end
1094
+ end
1095
+
1096
+ it '#fetch bit column (64bit)' do
1097
+ @m.query 'create temporary table t (i bit(64))'
1098
+ @m.query 'insert into t values (0),(-1),(4294967296),(18446744073709551615),(18446744073709551616)'
1099
+ @s.prepare 'select i from t'
1100
+ @s.execute
1101
+ if defined? Encoding
1102
+ @s.entries.should == [
1103
+ ["\x00\x00\x00\x00\x00\x00\x00\x00".force_encoding('ASCII-8BIT')],
1104
+ ["\xff\xff\xff\xff\xff\xff\xff\xff".force_encoding('ASCII-8BIT')],
1105
+ ["\x00\x00\x00\x01\x00\x00\x00\x00".force_encoding('ASCII-8BIT')],
1106
+ ["\xff\xff\xff\xff\xff\xff\xff\xff".force_encoding('ASCII-8BIT')],
1107
+ ["\xff\xff\xff\xff\xff\xff\xff\xff".force_encoding('ASCII-8BIT')],
1108
+ ]
1109
+ else
1110
+ @s.entries.should == [
1111
+ ["\x00\x00\x00\x00\x00\x00\x00\x00"],
1112
+ ["\xff\xff\xff\xff\xff\xff\xff\xff"],
1113
+ ["\x00\x00\x00\x01\x00\x00\x00\x00"],
1114
+ ["\xff\xff\xff\xff\xff\xff\xff\xff"],
1115
+ ["\xff\xff\xff\xff\xff\xff\xff\xff"],
1116
+ ]
1117
+ end
1118
+ end
1119
+
1120
+ it '#fetch tinyint column' do
1121
+ @m.query 'create temporary table t (i tinyint)'
1122
+ @m.query 'insert into t values (0),(-1),(127),(-128),(255),(-255)'
1123
+ @s.prepare 'select i from t'
1124
+ @s.execute
1125
+ @s.entries.should == [[0], [-1], [127], [-128], [127], [-128]]
1126
+ end
1127
+
1128
+ it '#fetch tinyint unsigned column' do
1129
+ @m.query 'create temporary table t (i tinyint unsigned)'
1130
+ @m.query 'insert into t values (0),(-1),(127),(-128),(255),(-255),(256)'
1131
+ @s.prepare 'select i from t'
1132
+ @s.execute
1133
+ @s.entries.should == [[0], [0], [127], [0], [255], [0], [255]]
1134
+ end
1135
+
1136
+ it '#fetch smallint column' do
1137
+ @m.query 'create temporary table t (i smallint)'
1138
+ @m.query 'insert into t values (0),(-1),(32767),(-32768),(65535),(-65535),(65536)'
1139
+ @s.prepare 'select i from t'
1140
+ @s.execute
1141
+ @s.entries.should == [[0], [-1], [32767], [-32768], [32767], [-32768], [32767]]
1142
+ end
1143
+
1144
+ it '#fetch smallint unsigned column' do
1145
+ @m.query 'create temporary table t (i smallint unsigned)'
1146
+ @m.query 'insert into t values (0),(-1),(32767),(-32768),(65535),(-65535),(65536)'
1147
+ @s.prepare 'select i from t'
1148
+ @s.execute
1149
+ @s.entries.should == [[0], [0], [32767], [0], [65535], [0], [65535]]
1150
+ end
1151
+
1152
+ it '#fetch mediumint column' do
1153
+ @m.query 'create temporary table t (i mediumint)'
1154
+ @m.query 'insert into t values (0),(-1),(8388607),(-8388608),(16777215),(-16777215),(16777216)'
1155
+ @s.prepare 'select i from t'
1156
+ @s.execute
1157
+ @s.entries.should == [[0], [-1], [8388607], [-8388608], [8388607], [-8388608], [8388607]]
1158
+ end
1159
+
1160
+ it '#fetch mediumint unsigned column' do
1161
+ @m.query 'create temporary table t (i mediumint unsigned)'
1162
+ @m.query 'insert into t values (0),(-1),(8388607),(-8388608),(16777215),(-16777215),(16777216)'
1163
+ @s.prepare 'select i from t'
1164
+ @s.execute
1165
+ @s.entries.should == [[0], [0], [8388607], [0], [16777215], [0], [16777215]]
1166
+ end
1167
+
1168
+ it '#fetch int column' do
1169
+ @m.query 'create temporary table t (i int)'
1170
+ @m.query 'insert into t values (0),(-1),(2147483647),(-2147483648),(4294967295),(-4294967295),(4294967296)'
1171
+ @s.prepare 'select i from t'
1172
+ @s.execute
1173
+ @s.entries.should == [[0], [-1], [2147483647], [-2147483648], [2147483647], [-2147483648], [2147483647]]
1174
+ end
1175
+
1176
+ it '#fetch int unsigned column' do
1177
+ @m.query 'create temporary table t (i int unsigned)'
1178
+ @m.query 'insert into t values (0),(-1),(2147483647),(-2147483648),(4294967295),(-4294967295),(4294967296)'
1179
+ @s.prepare 'select i from t'
1180
+ @s.execute
1181
+ @s.entries.should == [[0], [0], [2147483647], [0], [4294967295], [0], [4294967295]]
1182
+ end
1183
+
1184
+ it '#fetch bigint column' do
1185
+ @m.query 'create temporary table t (i bigint)'
1186
+ @m.query 'insert into t values (0),(-1),(9223372036854775807),(-9223372036854775808),(18446744073709551615),(-18446744073709551615),(18446744073709551616)'
1187
+ @s.prepare 'select i from t'
1188
+ @s.execute
1189
+ @s.entries.should == [[0], [-1], [9223372036854775807], [-9223372036854775808], [9223372036854775807], [-9223372036854775808], [9223372036854775807]]
1190
+ end
1191
+
1192
+ it '#fetch bigint unsigned column' do
1193
+ @m.query 'create temporary table t (i bigint unsigned)'
1194
+ @m.query 'insert into t values (0),(-1),(9223372036854775807),(-9223372036854775808),(18446744073709551615),(-18446744073709551615),(18446744073709551616)'
1195
+ @s.prepare 'select i from t'
1196
+ @s.execute
1197
+ @s.entries.should == [[0], [0], [9223372036854775807], [0], [18446744073709551615], [0], [18446744073709551615]]
1198
+ end
1199
+
1200
+ it '#fetch float column' do
1201
+ @m.query 'create temporary table t (i float)'
1202
+ @m.query 'insert into t values (0),(-3.402823466E+38),(-1.175494351E-38),(1.175494351E-38),(3.402823466E+38)'
1203
+ @s.prepare 'select i from t'
1204
+ @s.execute
1205
+ @s.fetch[0].should == 0.0
1206
+ (@s.fetch[0] - -3.402823466E+38).abs.should < 0.000000001E+38
1207
+ (@s.fetch[0] - -1.175494351E-38).abs.should < 0.000000001E-38
1208
+ (@s.fetch[0] - 1.175494351E-38).abs.should < 0.000000001E-38
1209
+ (@s.fetch[0] - 3.402823466E+38).abs.should < 0.000000001E+38
1210
+ end
1211
+
1212
+ it '#fetch float unsigned column' do
1213
+ @m.query 'create temporary table t (i float unsigned)'
1214
+ @m.query 'insert into t values (0),(-3.402823466E+38),(-1.175494351E-38),(1.175494351E-38),(3.402823466E+38)'
1215
+ @s.prepare 'select i from t'
1216
+ @s.execute
1217
+ @s.fetch[0].should == 0.0
1218
+ @s.fetch[0].should == 0.0
1219
+ @s.fetch[0].should == 0.0
1220
+ (@s.fetch[0] - 1.175494351E-38).abs.should < 0.000000001E-38
1221
+ (@s.fetch[0] - 3.402823466E+38).abs.should < 0.000000001E+38
1222
+ end
1223
+
1224
+ it '#fetch double column' do
1225
+ @m.query 'create temporary table t (i double)'
1226
+ @m.query 'insert into t values (0),(-1.7976931348623157E+308),(-2.2250738585072014E-308),(2.2250738585072014E-308),(1.7976931348623157E+308)'
1227
+ @s.prepare 'select i from t'
1228
+ @s.execute
1229
+ @s.fetch[0].should == 0.0
1230
+ (@s.fetch[0] - -Float::MAX).abs.should < Float::EPSILON
1231
+ (@s.fetch[0] - -Float::MIN).abs.should < Float::EPSILON
1232
+ (@s.fetch[0] - Float::MIN).abs.should < Float::EPSILON
1233
+ (@s.fetch[0] - Float::MAX).abs.should < Float::EPSILON
1234
+ end
1235
+
1236
+ it '#fetch double unsigned column' do
1237
+ @m.query 'create temporary table t (i double unsigned)'
1238
+ @m.query 'insert into t values (0),(-1.7976931348623157E+308),(-2.2250738585072014E-308),(2.2250738585072014E-308),(1.7976931348623157E+308)'
1239
+ @s.prepare 'select i from t'
1240
+ @s.execute
1241
+ @s.fetch[0].should == 0.0
1242
+ @s.fetch[0].should == 0.0
1243
+ @s.fetch[0].should == 0.0
1244
+ (@s.fetch[0] - Float::MIN).abs.should < Float::EPSILON
1245
+ (@s.fetch[0] - Float::MAX).abs.should < Float::EPSILON
1246
+ end
1247
+
1248
+ it '#fetch decimal column' do
1249
+ @m.query 'create temporary table t (i decimal)'
1250
+ @m.query 'insert into t values (0),(9999999999),(-9999999999),(10000000000),(-10000000000)'
1251
+ @s.prepare 'select i from t'
1252
+ @s.execute
1253
+ @s.entries.should == [["0"], ["9999999999"], ["-9999999999"], ["9999999999"], ["-9999999999"]]
1254
+ end
1255
+
1256
+ it '#fetch decimal unsigned column' do
1257
+ @m.query 'create temporary table t (i decimal unsigned)'
1258
+ @m.query 'insert into t values (0),(9999999998),(9999999999),(-9999999998),(-9999999999),(10000000000),(-10000000000)'
1259
+ @s.prepare 'select i from t'
1260
+ @s.execute
1261
+ @s.entries.should == [["0"], ["9999999998"], ["9999999999"], ["0"], ["0"], ["9999999999"], ["0"]]
1262
+ end
1263
+
1264
+ it '#fetch date column' do
1265
+ @m.query 'create temporary table t (i date)'
1266
+ @m.query "insert into t values ('0000-00-00'),('1000-01-01'),('9999-12-31')"
1267
+ @s.prepare 'select i from t'
1268
+ @s.execute
1269
+ @s.fetch.should == [Mysql::Time.new]
1270
+ @s.fetch.should == [Mysql::Time.new(1000,1,1)]
1271
+ @s.fetch.should == [Mysql::Time.new(9999,12,31)]
1272
+ end
1273
+
1274
+ it '#fetch datetime column' do
1275
+ @m.query 'create temporary table t (i datetime)'
1276
+ @m.query "insert into t values ('0000-00-00 00:00:00'),('1000-01-01 00:00:00'),('9999-12-31 23:59:59')"
1277
+ @s.prepare 'select i from t'
1278
+ @s.execute
1279
+ @s.fetch.should == [Mysql::Time.new]
1280
+ @s.fetch.should == [Mysql::Time.new(1000,1,1)]
1281
+ @s.fetch.should == [Mysql::Time.new(9999,12,31,23,59,59)]
1282
+ end
1283
+
1284
+ it '#fetch timestamp column' do
1285
+ @m.query 'create temporary table t (i timestamp)'
1286
+ @m.query("insert into t values ('1970-01-02 00:00:00'),('2037-12-30 23:59:59')")
1287
+ @s.prepare 'select i from t'
1288
+ @s.execute
1289
+ @s.fetch.should == [Mysql::Time.new(1970,1,2)]
1290
+ @s.fetch.should == [Mysql::Time.new(2037,12,30,23,59,59)]
1291
+ end
1292
+
1293
+ it '#fetch time column' do
1294
+ @m.query 'create temporary table t (i time)'
1295
+ @m.query "insert into t values ('-838:59:59'),(0),('838:59:59')"
1296
+ @s.prepare 'select i from t'
1297
+ @s.execute
1298
+ @s.fetch.should == [Mysql::Time.new(0,0,0,838,59,59,true)]
1299
+ @s.fetch.should == [Mysql::Time.new(0,0,0,0,0,0,false)]
1300
+ @s.fetch.should == [Mysql::Time.new(0,0,0,838,59,59,false)]
1301
+ end
1302
+
1303
+ it '#fetch year column' do
1304
+ @m.query 'create temporary table t (i year)'
1305
+ @m.query 'insert into t values (0),(70),(69),(1901),(2155)'
1306
+ @s.prepare 'select i from t'
1307
+ @s.execute
1308
+ @s.entries.should == [[0], [1970], [2069], [1901], [2155]]
1309
+ end
1310
+
1311
+ it '#fetch char column' do
1312
+ @m.query 'create temporary table t (i char(10))'
1313
+ @m.query "insert into t values (null),('abc')"
1314
+ @s.prepare 'select i from t'
1315
+ @s.execute
1316
+ @s.entries.should == [[nil], ['abc']]
1317
+ end
1318
+
1319
+ it '#fetch varchar column' do
1320
+ @m.query 'create temporary table t (i varchar(10))'
1321
+ @m.query "insert into t values (null),('abc')"
1322
+ @s.prepare 'select i from t'
1323
+ @s.execute
1324
+ @s.entries.should == [[nil], ['abc']]
1325
+ end
1326
+
1327
+ it '#fetch binary column' do
1328
+ @m.query 'create temporary table t (i binary(10))'
1329
+ @m.query "insert into t values (null),('abc')"
1330
+ @s.prepare 'select i from t'
1331
+ @s.execute
1332
+ @s.entries.should == [[nil], ["abc\0\0\0\0\0\0\0"]]
1333
+ end
1334
+
1335
+ it '#fetch varbinary column' do
1336
+ @m.query 'create temporary table t (i varbinary(10))'
1337
+ @m.query "insert into t values (null),('abc')"
1338
+ @s.prepare 'select i from t'
1339
+ @s.execute
1340
+ @s.entries.should == [[nil], ["abc"]]
1341
+ end
1342
+
1343
+ it '#fetch tinyblob column' do
1344
+ @m.query 'create temporary table t (i tinyblob)'
1345
+ @m.query "insert into t values (null),('abc')"
1346
+ @s.prepare 'select i from t'
1347
+ @s.execute
1348
+ @s.entries.should == [[nil], ["abc"]]
1349
+ end
1350
+
1351
+ it '#fetch tinytext column' do
1352
+ @m.query 'create temporary table t (i tinytext)'
1353
+ @m.query "insert into t values (null),('abc')"
1354
+ @s.prepare 'select i from t'
1355
+ @s.execute
1356
+ @s.entries.should == [[nil], ["abc"]]
1357
+ end
1358
+
1359
+ it '#fetch blob column' do
1360
+ @m.query 'create temporary table t (i blob)'
1361
+ @m.query "insert into t values (null),('abc')"
1362
+ @s.prepare 'select i from t'
1363
+ @s.execute
1364
+ @s.entries.should == [[nil], ["abc"]]
1365
+ end
1366
+
1367
+ it '#fetch text column' do
1368
+ @m.query 'create temporary table t (i text)'
1369
+ @m.query "insert into t values (null),('abc')"
1370
+ @s.prepare 'select i from t'
1371
+ @s.execute
1372
+ @s.entries.should == [[nil], ["abc"]]
1373
+ end
1374
+
1375
+ it '#fetch mediumblob column' do
1376
+ @m.query 'create temporary table t (i mediumblob)'
1377
+ @m.query "insert into t values (null),('abc')"
1378
+ @s.prepare 'select i from t'
1379
+ @s.execute
1380
+ @s.entries.should == [[nil], ["abc"]]
1381
+ end
1382
+
1383
+ it '#fetch mediumtext column' do
1384
+ @m.query 'create temporary table t (i mediumtext)'
1385
+ @m.query "insert into t values (null),('abc')"
1386
+ @s.prepare 'select i from t'
1387
+ @s.execute
1388
+ @s.entries.should == [[nil], ["abc"]]
1389
+ end
1390
+
1391
+ it '#fetch longblob column' do
1392
+ @m.query 'create temporary table t (i longblob)'
1393
+ @m.query "insert into t values (null),('abc')"
1394
+ @s.prepare 'select i from t'
1395
+ @s.execute
1396
+ @s.entries.should == [[nil], ["abc"]]
1397
+ end
1398
+
1399
+ it '#fetch longtext column' do
1400
+ @m.query 'create temporary table t (i longtext)'
1401
+ @m.query "insert into t values (null),('abc')"
1402
+ @s.prepare 'select i from t'
1403
+ @s.execute
1404
+ @s.entries.should == [[nil], ["abc"]]
1405
+ end
1406
+
1407
+ it '#fetch enum column' do
1408
+ @m.query "create temporary table t (i enum('abc','def'))"
1409
+ @m.query "insert into t values (null),(0),(1),(2),('abc'),('def'),('ghi')"
1410
+ @s.prepare 'select i from t'
1411
+ @s.execute
1412
+ @s.entries.should == [[nil], [''], ['abc'], ['def'], ['abc'], ['def'], ['']]
1413
+ end
1414
+
1415
+ it '#fetch set column' do
1416
+ @m.query "create temporary table t (i set('abc','def'))"
1417
+ @m.query "insert into t values (null),(0),(1),(2),(3),('abc'),('def'),('abc,def'),('ghi')"
1418
+ @s.prepare 'select i from t'
1419
+ @s.execute
1420
+ @s.entries.should == [[nil], [''], ['abc'], ['def'], ['abc,def'], ['abc'], ['def'], ['abc,def'], ['']]
1421
+ end
1422
+
1423
+ it '#field_count' do
1424
+ @s.prepare 'select 1,2,3'
1425
+ @s.field_count.should == 3
1426
+ @s.prepare 'set @a=1'
1427
+ @s.field_count.should == 0
1428
+ end
1429
+
1430
+ it '#free_result' do
1431
+ @s.free_result
1432
+ @s.prepare 'select 1,2,3'
1433
+ @s.execute
1434
+ @s.free_result
1435
+ end
1436
+
1437
+ it '#insert_id' do
1438
+ @m.query 'create temporary table t (i int auto_increment, unique(i))'
1439
+ @s.prepare 'insert into t values (0)'
1440
+ @s.execute
1441
+ @s.insert_id.should == 1
1442
+ @s.execute
1443
+ @s.insert_id.should == 2
1444
+ end
1445
+
1446
+ it '#num_rows' do
1447
+ @m.query 'create temporary table t (i int)'
1448
+ @m.query 'insert into t values (1),(2),(3),(4)'
1449
+ @s.prepare 'select * from t'
1450
+ @s.execute
1451
+ @s.num_rows.should == 4
1452
+ end
1453
+
1454
+ it '#param_count' do
1455
+ @m.query 'create temporary table t (a int, b int, c int)'
1456
+ @s.prepare 'select * from t'
1457
+ @s.param_count.should == 0
1458
+ @s.prepare 'insert into t values (?,?,?)'
1459
+ @s.param_count.should == 3
1460
+ end
1461
+
1462
+ it '#prepare' do
1463
+ @s.prepare('select 1').should be_kind_of Mysql::Stmt
1464
+ proc{@s.prepare 'invalid syntax'}.should raise_error Mysql::ParseError
1465
+ end
1466
+
1467
+ it '#prepare returns self' do
1468
+ @s.prepare('select 1').should == @s
1469
+ end
1470
+
1471
+ it '#prepare with invalid query raises error' do
1472
+ proc{@s.prepare 'invalid query'}.should raise_error Mysql::ParseError
1473
+ end
1474
+
1475
+ it '#result_metadata' do
1476
+ @s.prepare 'select 1 foo, 2 bar'
1477
+ f = @s.result_metadata.fetch_fields
1478
+ f[0].name.should == 'foo'
1479
+ f[1].name.should == 'bar'
1480
+ end
1481
+
1482
+ it '#result_metadata forn no data' do
1483
+ @s.prepare 'set @a=1'
1484
+ @s.result_metadata.should == nil
1485
+ end
1486
+
1487
+ it '#row_seek and #row_tell' do
1488
+ @m.query 'create temporary table t (i int)'
1489
+ @m.query 'insert into t values (0),(1),(2),(3),(4)'
1490
+ @s.prepare 'select * from t'
1491
+ @s.execute
1492
+ row0 = @s.row_tell
1493
+ @s.fetch.should == [0]
1494
+ @s.fetch.should == [1]
1495
+ row2 = @s.row_seek row0
1496
+ @s.fetch.should == [0]
1497
+ @s.row_seek row2
1498
+ @s.fetch.should == [2]
1499
+ end
1500
+
1501
+ it '#sqlstate' do
1502
+ @s.prepare 'select 1'
1503
+ @s.sqlstate.should == '00000'
1504
+ proc{@s.prepare 'hogehoge'}.should raise_error Mysql::ParseError
1505
+ @s.sqlstate.should == '42000'
1506
+ end
1507
+ end
1508
+
1509
+ describe 'Mysql::Time' do
1510
+ before do
1511
+ @t = Mysql::Time.new
1512
+ end
1513
+
1514
+ it '.new with no arguments returns 0' do
1515
+ @t.year.should == 0
1516
+ @t.month.should == 0
1517
+ @t.day.should == 0
1518
+ @t.hour.should == 0
1519
+ @t.minute.should == 0
1520
+ @t.second.should == 0
1521
+ @t.neg.should == false
1522
+ @t.second_part.should == 0
1523
+ end
1524
+
1525
+ it '#inspect' do
1526
+ Mysql::Time.new(2009,12,8,23,35,21).inspect.should == '#<Mysql::Time:2009-12-08 23:35:21>'
1527
+ end
1528
+
1529
+ it '#to_s' do
1530
+ Mysql::Time.new(2009,12,8,23,35,21).to_s.should == '2009-12-08 23:35:21'
1531
+ end
1532
+
1533
+ it '#to_i' do
1534
+ Mysql::Time.new(2009,12,8,23,35,21).to_i.should == 20091208233521
1535
+ end
1536
+
1537
+ it '#year' do
1538
+ (@t.year = 2009).should == 2009
1539
+ @t.year.should == 2009
1540
+ end
1541
+
1542
+ it '#month' do
1543
+ (@t.month = 12).should == 12
1544
+ @t.month.should == 12
1545
+ end
1546
+
1547
+ it '#day' do
1548
+ (@t.day = 8).should == 8
1549
+ @t.day.should == 8
1550
+ end
1551
+
1552
+ it '#hour' do
1553
+ (@t.hour = 23).should == 23
1554
+ @t.hour.should == 23
1555
+ end
1556
+
1557
+ it '#minute' do
1558
+ (@t.minute = 35).should == 35
1559
+ @t.minute.should == 35
1560
+ end
1561
+
1562
+ it '#second' do
1563
+ (@t.second = 21).should == 21
1564
+ @t.second.should == 21
1565
+ end
1566
+
1567
+ it '#neg' do
1568
+ @t.neg.should == false
1569
+ end
1570
+
1571
+ it '#second_part' do
1572
+ @t.second_part.should == 0
1573
+ end
1574
+
1575
+ it '#==' do
1576
+ t1 = Mysql::Time.new 2009,12,8,23,35,21
1577
+ t2 = Mysql::Time.new 2009,12,8,23,35,21
1578
+ t1.should == t2
1579
+ end
1580
+ end
1581
+
1582
+ describe 'Mysql::Error' do
1583
+ before do
1584
+ m = Mysql.connect(MYSQL_SERVER, MYSQL_USER, MYSQL_PASSWORD, MYSQL_DATABASE, MYSQL_PORT, MYSQL_SOCKET)
1585
+ begin
1586
+ m.query('hogehoge')
1587
+ rescue => @e
1588
+ end
1589
+ end
1590
+
1591
+ it '#error is error message' do
1592
+ @e.error.should == "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'hogehoge' at line 1"
1593
+ end
1594
+
1595
+ it '#errno is error number' do
1596
+ @e.errno.should == 1064
1597
+ end
1598
+
1599
+ it '#sqlstate is sqlstate value as String' do
1600
+ @e.sqlstate.should == '42000'
1601
+ end
1602
+ end
1603
+
1604
+ if defined? Encoding
1605
+ describe 'Connection charset is UTF-8:' do
1606
+ before do
1607
+ @m = Mysql.connect(MYSQL_SERVER, MYSQL_USER, MYSQL_PASSWORD, MYSQL_DATABASE, MYSQL_PORT, MYSQL_SOCKET)
1608
+ @m.charset = "utf8"
1609
+ @m.query "create temporary table t (utf8 char(10) charset utf8, cp932 char(10) charset cp932, eucjp char(10) charset eucjpms, bin varbinary(10))"
1610
+ @utf8 = "いろは"
1611
+ @cp932 = @utf8.encode "CP932"
1612
+ @eucjp = @utf8.encode "EUC-JP-MS"
1613
+ @bin = "\x00\x01\x7F\x80\xFE\xFF".force_encoding("ASCII-8BIT")
1614
+ @default_internal = Encoding.default_internal
1615
+ end
1616
+
1617
+ after do
1618
+ Encoding.default_internal = @default_internal
1619
+ end
1620
+
1621
+ describe 'default_internal is CP932' do
1622
+ before do
1623
+ Encoding.default_internal = 'CP932'
1624
+ end
1625
+ it 'is converted to CP932' do
1626
+ @m.query('select "あいう"').fetch.should == ["\x82\xA0\x82\xA2\x82\xA4".force_encoding("CP932")]
1627
+ end
1628
+ end
1629
+
1630
+ describe 'query with CP932 encoding' do
1631
+ it 'is converted to UTF-8' do
1632
+ @m.query('select HEX("あいう")'.encode("CP932")).fetch.should == ["E38182E38184E38186"]
1633
+ end
1634
+ end
1635
+
1636
+ describe 'prepared statement with CP932 encoding' do
1637
+ it 'is converted to UTF-8' do
1638
+ @m.prepare('select HEX("あいう")'.encode("CP932")).execute.fetch.should == ["E38182E38184E38186"]
1639
+ end
1640
+ end
1641
+
1642
+ describe 'The encoding of data are correspond to charset of column:' do
1643
+ before do
1644
+ @m.prepare("insert into t (utf8,cp932,eucjp,bin) values (?,?,?,?)").execute @utf8, @cp932, @eucjp, @bin
1645
+ end
1646
+ it 'data is stored as is' do
1647
+ @m.query('select hex(utf8),hex(cp932),hex(eucjp),hex(bin) from t').fetch.should == ['E38184E3828DE381AF', '82A282EB82CD', 'A4A4A4EDA4CF', '00017F80FEFF']
1648
+ end
1649
+ it 'By simple query, charset of retrieved data is connection charset' do
1650
+ @m.query('select utf8,cp932,eucjp,bin from t').fetch.should == [@utf8, @utf8, @utf8, @bin.dup.force_encoding("UTF-8")]
1651
+ end
1652
+ it 'By prepared statement, charset of retrieved data is connection charset except for binary' do
1653
+ @m.prepare('select utf8,cp932,eucjp,bin from t').execute.fetch.should == [@utf8, @utf8, @utf8, @bin]
1654
+ end
1655
+ end
1656
+
1657
+ describe 'The encoding of data are different from charset of column:' do
1658
+ before do
1659
+ @m.prepare("insert into t (utf8,cp932,eucjp,bin) values (?,?,?,?)").execute @utf8, @utf8, @utf8, @utf8
1660
+ end
1661
+ it 'stored data is converted' do
1662
+ @m.query("select hex(utf8),hex(cp932),hex(eucjp),hex(bin) from t").fetch.should == ["E38184E3828DE381AF", "82A282EB82CD", "A4A4A4EDA4CF", "E38184E3828DE381AF"]
1663
+ end
1664
+ it 'By simple query, charset of retrieved data is connection charset' do
1665
+ @m.query("select utf8,cp932,eucjp,bin from t").fetch.should == [@utf8, @utf8, @utf8, @utf8]
1666
+ end
1667
+ it 'By prepared statement, charset of retrieved data is connection charset except for binary' do
1668
+ @m.prepare("select utf8,cp932,eucjp,bin from t").execute.fetch.should == [@utf8, @utf8, @utf8, @utf8.dup.force_encoding("ASCII-8BIT")]
1669
+ end
1670
+ end
1671
+
1672
+ describe 'The data include invalid byte code:' do
1673
+ it 'raises Encoding::InvalidByteSequenceError' do
1674
+ cp932 = "\x01\xFF\x80".force_encoding("CP932")
1675
+ proc{@m.prepare("insert into t (cp932) values (?)").execute cp932}.should raise_error(Encoding::InvalidByteSequenceError)
1676
+ end
1677
+ end
1678
+ end
1679
+ end