ruby-mysql2 0.5.4

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.
@@ -0,0 +1,176 @@
1
+ module Mysql2
2
+ # Mysql2::Result
3
+ class Result
4
+ attr_reader :server_flags
5
+
6
+ include Enumerable
7
+
8
+ # @param result [Mysql::Result]
9
+ # @param options [Hash]
10
+ def initialize(result, options)
11
+ @result = result
12
+ @query_options = options
13
+ server_status = result.server_status
14
+ @server_flags = {
15
+ no_good_index_used: server_status & Mysql::SERVER_QUERY_NO_GOOD_INDEX_USED != 0,
16
+ no_index_used: server_status & Mysql::SERVER_QUERY_NO_INDEX_USED != 0,
17
+ query_was_slow: server_status & Mysql::SERVER_QUERY_WAS_SLOW != 0,
18
+ }
19
+ end
20
+
21
+ def size
22
+ @result.size
23
+ end
24
+ alias count size
25
+
26
+ def free
27
+ # dummy
28
+ end
29
+
30
+ def fields
31
+ @result.fields.map{|f| f.name.freeze}
32
+ end
33
+
34
+ def field_types
35
+ @result.fields.map{|f| field_type_string(f)}
36
+ end
37
+
38
+ def each(**opts, &block)
39
+ opts = @query_options.merge(opts)
40
+
41
+ raise Mysql2::Error, 'Result set has already been freed' if opts[:stream] && @all_retrieved
42
+ return enum_for(:each, **opts) unless block
43
+
44
+ @pos ||= 0
45
+ @cached ||= []
46
+ @pos = 0 unless opts[:stream]
47
+
48
+ while @pos < @cached.size
49
+ block.call @cached[@pos]
50
+ @pos += 1
51
+ end
52
+
53
+ @result.data_seek @pos
54
+ while (row = @result.fetch(**opts))
55
+ row = @result.fields.map.with_index do |f, i|
56
+ opts[:cast] ? convert_type(row[i], f, opts) : row[i]
57
+ end
58
+ if opts[:as] == :hash
59
+ row = @result.fields.map.with_index.to_h do |f, i|
60
+ key = opts[:symbolize_keys] ? f.name.intern : f.name
61
+ [key, row[i]]
62
+ end
63
+ end
64
+ @cached.push row if opts[:cache_rows]
65
+ @pos += 1
66
+ block.call row
67
+ end
68
+ @all_retrieved = true
69
+ self
70
+ rescue Mysql::Error => e
71
+ raise Mysql2::Error, e.message
72
+ end
73
+
74
+ FIELD_TYPE_STRING = {
75
+ Mysql::Field::TYPE_DECIMAL => "decimal",
76
+ Mysql::Field::TYPE_TINY => "tinyint",
77
+ Mysql::Field::TYPE_SHORT => "smallint",
78
+ Mysql::Field::TYPE_LONG => "int",
79
+ Mysql::Field::TYPE_FLOAT => "float",
80
+ Mysql::Field::TYPE_DOUBLE => "double",
81
+ Mysql::Field::TYPE_NULL => "null",
82
+ Mysql::Field::TYPE_TIMESTAMP => "timestamp",
83
+ Mysql::Field::TYPE_LONGLONG => "bigint",
84
+ Mysql::Field::TYPE_INT24 => "mediumint",
85
+ Mysql::Field::TYPE_DATE => "date",
86
+ Mysql::Field::TYPE_TIME => "time",
87
+ Mysql::Field::TYPE_DATETIME => "datetime",
88
+ Mysql::Field::TYPE_YEAR => "year",
89
+ Mysql::Field::TYPE_NEWDATE => "date",
90
+ Mysql::Field::TYPE_VARCHAR => "varchar",
91
+ Mysql::Field::TYPE_BIT => "bit",
92
+ Mysql::Field::TYPE_TIMESTAMP2 => "timestamp",
93
+ Mysql::Field::TYPE_DATETIME2 => "datetime",
94
+ Mysql::Field::TYPE_TIME2 => "time",
95
+ Mysql::Field::TYPE_TYPED_ARRAY => "typed_array",
96
+ Mysql::Field::TYPE_INVALID => "invalid",
97
+ Mysql::Field::TYPE_BOOL => "bool",
98
+ Mysql::Field::TYPE_JSON => "json",
99
+ Mysql::Field::TYPE_NEWDECIMAL => "decimal",
100
+ Mysql::Field::TYPE_ENUM => "enum",
101
+ Mysql::Field::TYPE_SET => "set",
102
+ Mysql::Field::TYPE_TINY_BLOB => "tinyblob",
103
+ Mysql::Field::TYPE_MEDIUM_BLOB => "mediumblob",
104
+ Mysql::Field::TYPE_LONG_BLOB => "longblob",
105
+ Mysql::Field::TYPE_BLOB => "blob",
106
+ Mysql::Field::TYPE_VAR_STRING => "varchar",
107
+ Mysql::Field::TYPE_STRING => "char",
108
+ Mysql::Field::TYPE_GEOMETRY => "geometry",
109
+ Mysql::Field::TYPE_CHAR => "tinyint",
110
+ Mysql::Field::TYPE_INTERVAL => "interval",
111
+ }.freeze
112
+
113
+ BINARY_CHARSET = 63
114
+
115
+ def field_type_string(field)
116
+ if field.type == Mysql::Field::TYPE_STRING
117
+ return 'enum' if field.flags & Mysql::Field::ENUM_FLAG != 0
118
+ return 'set' if field.flags & Mysql::Field::SET_FLAG != 0
119
+ end
120
+ type = FIELD_TYPE_STRING[field.type]
121
+ if type =~ /int$|bit$|year$/
122
+ type += "(#{field.length})"
123
+ elsif type =~ /char$/
124
+ if field.charsetnr == BINARY_CHARSET
125
+ type = type.sub(/char/, 'binary') + "(#{field.length})"
126
+ else
127
+ type += "(#{field.length / 3})"
128
+ end
129
+ elsif type =~ /float|double/
130
+ type += "(#{field.length},#{field.decimals})"
131
+ elsif type == 'decimal'
132
+ type += "(#{field.length - (field.decimals > 0 ? 2 : 1)},#{field.decimals})"
133
+ elsif type == 'blob'
134
+ if field.charsetnr == BINARY_CHARSET
135
+ case field.length
136
+ when 255
137
+ type = 'tinyblob'
138
+ when 65535
139
+ type = 'blob'
140
+ when 16777215
141
+ type = 'mediumblob'
142
+ when 4294967295
143
+ type = 'longblob'
144
+ end
145
+ else
146
+ type = 'text'
147
+ case field.length
148
+ when 255 * 3
149
+ type = 'tinytext'
150
+ when 65535 * 3
151
+ type = 'text'
152
+ when 16777215 * 3
153
+ type = 'mediumtext'
154
+ when 4294967295
155
+ type = 'longtext'
156
+ end
157
+ end
158
+ end
159
+ type
160
+ end
161
+
162
+ def convert_type(value, field, opts)
163
+ return nil if value.nil?
164
+ case field.type
165
+ when Mysql::Field::TYPE_BIT
166
+ opts[:cast_booleans] ? value != "\x00" : value
167
+ when Mysql::Field::TYPE_TINY
168
+ opts[:cast_booleans] && field.length == 1 ? value != 0 : value
169
+ when Mysql::Field::TYPE_TIME
170
+ Time.new(2000, 1, 1) + value
171
+ else
172
+ value
173
+ end
174
+ end
175
+ end
176
+ end
@@ -0,0 +1,103 @@
1
+ module Mysql2
2
+ class Statement
3
+ # @param stmt [Mysql::Stmt]
4
+ def initialize(stmt, **opts)
5
+ @stmt = stmt
6
+ @opts = opts
7
+ end
8
+
9
+ def param_count
10
+ @stmt.param_count
11
+ end
12
+
13
+ def field_count
14
+ @stmt.field_count
15
+ end
16
+
17
+ def fields
18
+ field_count == 0 ? nil : @stmt.fields.map(&:name)
19
+ end
20
+
21
+ def execute(*args, **opts)
22
+ res = @stmt.execute(*args, **opts)
23
+ opts = @opts.merge(opts)
24
+ StatementResult.new(res, **opts)
25
+ rescue Mysql::Error => e
26
+ raise Mysql2::Error, e.message
27
+ end
28
+
29
+ def affected_rows
30
+ @stmt.affected_rows
31
+ end
32
+
33
+ def last_id
34
+ @stmt.insert_id
35
+ end
36
+
37
+ def close
38
+ @stmt.close
39
+ end
40
+ end
41
+
42
+ class StatementResult
43
+ include Enumerable
44
+
45
+ def initialize(result, **opts)
46
+ if !opts[:cache_rows] && !opts[:stream]
47
+ warn ':cache_rows is forced for prepared statements (if not streaming)'
48
+ end
49
+ @result = result
50
+ @opts = opts
51
+ end
52
+
53
+ def each(**opts, &block)
54
+ opts = @opts.merge(opts)
55
+
56
+ raise Mysql2::Error, 'Result set has already been freed' if opts[:stream] && @all_retrieved
57
+ return enum_for(:each, **opts) unless block
58
+
59
+ @pos ||= 0
60
+ @cached ||= []
61
+ @pos = 0 unless opts[:stream]
62
+
63
+ while @pos < @cached.size
64
+ block.call @cached[@pos]
65
+ @pos += 1
66
+ end
67
+
68
+ @result.data_seek @pos
69
+ while (row = @result.fetch(**opts))
70
+ row = @result.fields.map.with_index do |f, i|
71
+ convert_type(row[i], f, opts)
72
+ end
73
+ if opts[:as] == :hash
74
+ row = @result.fields.map.with_index.to_h do |f, i|
75
+ key = opts[:symbolize_keys] ? f.name.intern : f.name
76
+ [key, row[i]]
77
+ end
78
+ end
79
+ @cached.push row if opts[:cache_rows]
80
+ @pos += 1
81
+ block.call row
82
+ end
83
+ @all_retrieved = true
84
+ self
85
+ rescue Mysql::Error => e
86
+ raise Mysql2::Error, e.message
87
+ end
88
+
89
+ def convert_type(value, field, opts)
90
+ return nil if value.nil?
91
+ case field.type
92
+ when Mysql::Field::TYPE_BIT
93
+ opts[:cast_booleans] ? value != "\x00" : value
94
+ when Mysql::Field::TYPE_TINY
95
+ opts[:cast_booleans] && field.length == 1 ? value != 0 : value
96
+ when Mysql::Field::TYPE_TIME
97
+ Time.new(2000, 1, 1) + value
98
+ else
99
+ value
100
+ end
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,3 @@
1
+ module Mysql2
2
+ VERSION = "0.5.4".freeze
3
+ end
data/lib/mysql2.rb ADDED
@@ -0,0 +1,87 @@
1
+ require 'mysql'
2
+ require 'date'
3
+ require 'bigdecimal'
4
+
5
+ # Load libmysql.dll before requiring mysql2/mysql2.so
6
+ # This gives a chance to be flexible about the load path
7
+ # Or to bomb out with a clear error message instead of a linker crash
8
+ if RUBY_PLATFORM =~ /mswin|mingw/
9
+ dll_path = if ENV['RUBY_MYSQL2_LIBMYSQL_DLL']
10
+ # If this environment variable is set, it overrides any other paths
11
+ # The user is advised to use backslashes not forward slashes
12
+ ENV['RUBY_MYSQL2_LIBMYSQL_DLL']
13
+ elsif File.exist?(File.expand_path('../vendor/libmysql.dll', File.dirname(__FILE__)))
14
+ # Use vendor/libmysql.dll if it exists, convert slashes for Win32 LoadLibrary
15
+ File.expand_path('../vendor/libmysql.dll', File.dirname(__FILE__))
16
+ elsif defined?(RubyInstaller)
17
+ # RubyInstaller-2.4+ native build doesn't need DLL preloading
18
+ else
19
+ # This will use default / system library paths
20
+ 'libmysql.dll'
21
+ end
22
+
23
+ if dll_path
24
+ require 'fiddle'
25
+ kernel32 = Fiddle.dlopen 'kernel32'
26
+ load_library = Fiddle::Function.new(
27
+ kernel32['LoadLibraryW'], [Fiddle::TYPE_VOIDP], Fiddle::TYPE_INT,
28
+ )
29
+ if load_library.call(dll_path.encode('utf-16le')).zero?
30
+ abort "Failed to load libmysql.dll from #{dll_path}"
31
+ end
32
+ end
33
+ end
34
+
35
+ require 'mysql2/version' unless defined? Mysql2::VERSION
36
+ require 'mysql2/error'
37
+ require 'mysql2/result'
38
+ require 'mysql2/client'
39
+ require 'mysql2/field'
40
+ require 'mysql2/statement'
41
+
42
+ # = Mysql2
43
+ #
44
+ # A modern, simple and very fast Mysql library for Ruby - binding to libmysql
45
+ module Mysql2
46
+ end
47
+
48
+ if defined?(ActiveRecord::VERSION::STRING) && ActiveRecord::VERSION::STRING < "3.1"
49
+ begin
50
+ require 'active_record/connection_adapters/mysql2_adapter'
51
+ rescue LoadError
52
+ warn "============= WARNING FROM mysql2 ============="
53
+ warn "This version of mysql2 (#{Mysql2::VERSION}) doesn't ship with the ActiveRecord adapter."
54
+ warn "In Rails version 3.1.0 and up, the mysql2 ActiveRecord adapter is included with rails."
55
+ warn "If you want to use the mysql2 gem with Rails <= 3.0.x, please use the latest mysql2 in the 0.2.x series."
56
+ warn "============= END WARNING FROM mysql2 ============="
57
+ end
58
+ end
59
+
60
+ # For holding utility methods
61
+ module Mysql2
62
+ module Util
63
+ #
64
+ # Rekey a string-keyed hash with equivalent symbols.
65
+ #
66
+ def self.key_hash_as_symbols(hash)
67
+ return nil unless hash
68
+ Hash[hash.map { |k, v| [k.to_sym, v] }]
69
+ end
70
+
71
+ #
72
+ # In Mysql2::Client#query and Mysql2::Statement#execute,
73
+ # Thread#handle_interrupt is used to prevent Timeout#timeout
74
+ # from interrupting query execution.
75
+ #
76
+ # Timeout::ExitException was removed in Ruby 2.3.0, 2.2.3, and 2.1.8,
77
+ # but is present in earlier 2.1.x and 2.2.x, so we provide a shim.
78
+ #
79
+ require 'timeout'
80
+ TIMEOUT_ERROR_CLASS = if defined?(::Timeout::ExitException)
81
+ ::Timeout::ExitException
82
+ else
83
+ ::Timeout::Error
84
+ end
85
+ TIMEOUT_ERROR_NEVER = { TIMEOUT_ERROR_CLASS => :never }.freeze
86
+ end
87
+ end
metadata ADDED
@@ -0,0 +1,102 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ruby-mysql2
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.5.4
5
+ platform: ruby
6
+ authors:
7
+ - Tomita Masahiro
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2022-11-27 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: ruby-mysql
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '4.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '4.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rubocop
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description:
56
+ email: tommy@tmtm.org
57
+ executables: []
58
+ extensions: []
59
+ extra_rdoc_files: []
60
+ files:
61
+ - CHANGELOG.md
62
+ - LICENSE
63
+ - README.md
64
+ - README.org.md
65
+ - lib/mysql2.rb
66
+ - lib/mysql2/client.rb
67
+ - lib/mysql2/console.rb
68
+ - lib/mysql2/error.rb
69
+ - lib/mysql2/field.rb
70
+ - lib/mysql2/result.rb
71
+ - lib/mysql2/statement.rb
72
+ - lib/mysql2/version.rb
73
+ homepage: https://gitlab.com/tmtms/ruby-mysql2
74
+ licenses:
75
+ - MIT
76
+ metadata:
77
+ bug_tracker_uri: https://gitlab.com/tmtms/ruby-mysql2/issues
78
+ changelog_uri: https://gitlab.com/tmtms/ruby-mysql2/releases/tag/0.5.4
79
+ documentation_uri: https://www.rubydoc.info/gems/ruby-mysql2/0.5.4
80
+ homepage_uri: https://gitlab.com/tmtms/ruby-mysql2
81
+ source_code_uri: https://gitlab.com/tmtms/ruby-mysql2/tree/0.5.4
82
+ post_install_message:
83
+ rdoc_options:
84
+ - "--charset=UTF-8"
85
+ require_paths:
86
+ - lib
87
+ required_ruby_version: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - ">="
90
+ - !ruby/object:Gem::Version
91
+ version: 2.6.0
92
+ required_rubygems_version: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ requirements: []
98
+ rubygems_version: 3.4.0.dev
99
+ signing_key:
100
+ specification_version: 4
101
+ summary: Mysql2 compatible pure Ruby library
102
+ test_files: []