ruby-mysql2 0.5.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: []