mysql2-cs-bind 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in mysql2-cs-bind.gemspec
4
+ gemspec
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010-2011 Brian Lopez - http://github.com/brianmario
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,67 @@
1
+ # mysql-cs-bind
2
+
3
+ 'mysql-cs-bind' is extension of 'mysql2', to add method of client-side variable binding (pseudo prepared statement).
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'mysql2-cs-bind'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install mysql2-cs-bind
18
+
19
+ ## Usage
20
+
21
+ Require 'mysql2-cs-bind' instead of (or after) 'mysql2', you can use Mysql2::Client#xquery with bound variables like below:
22
+
23
+ use 'mysql2-cs-bind'
24
+ client = Mysql2::Client.new(...)
25
+ client.xquery('SELECT x,y,z FROM tbl WHERE x=? AND y=?', val1, val2) #=> Mysql2::Result
26
+
27
+ Mysql2::Client#xquery receives query, variables, and options(hash) for Mysql2::Client#query.
28
+
29
+ client.xquery(sql)
30
+ client.xquery(sql, :as => :array)
31
+ client.xquery(sql, val1, val2)
32
+ client.xquery(sql, [val1, val2])
33
+ client.xquery(sql, val1, val2, :as => :array)
34
+ client.xquery(sql, [val1, val2], :as => :array)
35
+
36
+ Mysql2::Client#xquery raises ArgumentError if mismatch found between placeholder number and arguments
37
+
38
+ client.xquery('SELECT x FROM tbl', 1) # ArgumentError
39
+ client.xquery('SELECT x FROM tbl WHERE x=? AND y=?', 1) # ArgumentError
40
+ client.xquery('SELECT x FROM tbl WHERE x=?', 1, 2) # ArgumentError
41
+
42
+ Formatting for nil and Time objects:
43
+
44
+ client.xquery('INSERT INTO tbl (val1,created_at) VALUES (?,?)', nil, Time.now)
45
+ #execute "INSERT INTO tbl (val1,created_at) VALUES (NULL,'2012-01-02 13:45:01')"
46
+
47
+ ### Type Conversion of Numbers
48
+
49
+ Mysql2::Client#xquery quotes any values as STRING. This may not be problems for almost all kind of queries, but sometimes you may be confused by return value types:
50
+
51
+ client.query('SELECT 1', :as => :array).first #=> [1]
52
+ client.xquery('SELECT ?', 1, :as => :array).first #=> ['1']
53
+
54
+ ## Contributing
55
+
56
+ 1. Fork it
57
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
58
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
59
+ 4. Push to the branch (`git push origin my-new-feature`)
60
+ 5. Create new Pull Request
61
+
62
+ ## Copyright
63
+
64
+ Copyright (c) 2012- TAGOMORI Satoshi (tagomoris)
65
+
66
+ ## License
67
+ MIT (see MIT-LICENSE)
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
@@ -0,0 +1,43 @@
1
+ require 'mysql2'
2
+
3
+ class Mysql2::Client
4
+
5
+ def xquery(sql, *args)
6
+ options = if args.size > 0 and args[-1].is_a?(Hash)
7
+ args.pop
8
+ else
9
+ {}
10
+ end
11
+ if args.size < 1
12
+ query(sql, options)
13
+ else
14
+ query(pseudo_bind(sql, args.flatten), options)
15
+ end
16
+ end
17
+
18
+ private
19
+ def pseudo_bind(sql, values)
20
+ sql = sql.dup
21
+
22
+ placeholders = []
23
+ search_pos = 0
24
+ while pos = sql.index('?', search_pos)
25
+ placeholders.push(pos)
26
+ search_pos = pos + 1
27
+ end
28
+ raise ArgumentError, "mismatch between placeholders number and values arguments" if placeholders.length != values.length
29
+
30
+ while pos = placeholders.pop()
31
+ rawvalue = values.pop()
32
+ if rawvalue.nil?
33
+ sql[pos] = 'NULL'
34
+ elsif rawvalue.is_a?(Time)
35
+ sql[pos] = "'" + rawvalue.strftime('%Y-%m-%d %H:%M:%S') + "'"
36
+ else
37
+ sql[pos] = "'" + Mysql2::Client.escape(rawvalue.to_s) + "'"
38
+ end
39
+ end
40
+ sql
41
+ end
42
+
43
+ end
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |gem|
4
+ gem.name = "mysql2-cs-bind"
5
+ gem.version = "0.0.1"
6
+ gem.authors = ["TAGOMORI Satoshi"]
7
+ gem.email = ["tagomoris@gmail.com"]
8
+ gem.homepage = "https://github.com/tagomoris/mysql2-cs-bind"
9
+ gem.summary = %q{extension for mysql2 to add client-side variable binding}
10
+ gem.description = %q{extension for mysql2 to add client-side variable binding, by adding method Mysql2::Client#xquery}
11
+
12
+ gem.files = `git ls-files`.split($\)
13
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
14
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
15
+ gem.require_paths = ["lib"]
16
+
17
+ gem.add_runtime_dependency "mysql2"
18
+
19
+ # tests
20
+ gem.add_development_dependency "mysql2"
21
+ gem.add_development_dependency 'eventmachine'
22
+ gem.add_development_dependency 'rake-compiler', "~> 0.7.7"
23
+ gem.add_development_dependency 'rake', '0.8.7' # NB: 0.8.7 required by rake-compiler 0.7.9
24
+ gem.add_development_dependency 'rspec'
25
+ end
@@ -0,0 +1,98 @@
1
+ # encoding: UTF-8
2
+ require 'spec_helper'
3
+
4
+ describe Mysql2::Client do
5
+ before(:each) do
6
+ @client = Mysql2::Client.new
7
+ end
8
+
9
+ it "should respond to #query" do
10
+ @client.should respond_to(:query)
11
+ end
12
+
13
+ context "#pseudo_bind" do
14
+ it "should return query just same as argument, if without any placeholders" do
15
+ @client.__send__(:pseudo_bind, "SELECT x,y,z FROM x WHERE x='1'", []).should eql("SELECT x,y,z FROM x WHERE x='1'")
16
+ end
17
+
18
+ it "should return replaced query if with placeholders" do
19
+ @client.__send__(:pseudo_bind, "SELECT x,y,z FROM x WHERE x=?", [1]).should eql("SELECT x,y,z FROM x WHERE x='1'")
20
+ @client.__send__(:pseudo_bind, "SELECT x,y,z FROM x WHERE x=? AND y=?", [1, 'X']).should eql("SELECT x,y,z FROM x WHERE x='1' AND y='X'")
21
+ end
22
+
23
+ it "should raise ArgumentError if mismatch exists between placeholders and arguments" do
24
+ expect {
25
+ @client.__send__(:pseudo_bind, "SELECT x,y,z FROM x", [1])
26
+ }.should raise_exception(ArgumentError)
27
+ expect {
28
+ @client.__send__(:pseudo_bind, "SELECT x,y,z FROM x WHERE x=?", [1,2])
29
+ }.should raise_exception(ArgumentError)
30
+ expect {
31
+ @client.__send__(:pseudo_bind, "SELECT x,y,z FROM x WHERE x=? AND y=?", [1])
32
+ }.should raise_exception(ArgumentError)
33
+ expect {
34
+ @client.__send__(:pseudo_bind, "SELECT x,y,z FROM x WHERE x=?", [])
35
+ }.should raise_exception(ArgumentError)
36
+ end
37
+
38
+ it "should replace placeholder with NULL about nil" do
39
+ @client.__send__(:pseudo_bind, "UPDATE x SET y=? WHERE x=?", [nil,1]).should eql("UPDATE x SET y=NULL WHERE x='1'")
40
+ end
41
+
42
+ it "should replace placeholder with formatted timestamp string about Time object" do
43
+ require 'time'
44
+ t = Time.strptime('2012/04/20 16:50:45', '%Y/%m/%d %H:%M:%S')
45
+ @client.__send__(:pseudo_bind, "UPDATE x SET y=? WHERE x=?", [t,1]).should eql("UPDATE x SET y='2012-04-20 16:50:45' WHERE x='1'")
46
+ end
47
+ end
48
+
49
+ context "#xquery" do
50
+ it "should let you query again if iterating is finished when streaming" do
51
+ @client.xquery("SELECT 1 UNION SELECT ?", 2, :stream => true, :cache_rows => false).each {}
52
+
53
+ expect {
54
+ @client.xquery("SELECT 1 UNION SELECT ?", 2, :stream => true, :cache_rows => false)
55
+ }.to_not raise_exception(Mysql2::Error)
56
+ end
57
+
58
+ it "should accept an options hash that inherits from Mysql2::Client.default_query_options" do
59
+ @client.xquery "SELECT ?", 1, :something => :else
60
+ @client.query_options.should eql(@client.query_options.merge(:something => :else))
61
+ end
62
+
63
+ it "should return results as a hash by default" do
64
+ @client.xquery("SELECT ?", 1).first.class.should eql(Hash)
65
+ end
66
+
67
+ it "should be able to return results as an array" do
68
+ @client.xquery("SELECT ?", 1, :as => :array).first.class.should eql(Array)
69
+ @client.xquery("SELECT ?", 1).each(:as => :array)
70
+ @client.query("SELECT 1").first.should eql([1])
71
+ @client.query("SELECT '1'").first.should eql(['1'])
72
+ @client.xquery("SELECT 1", :as => :array).first.should eql([1])
73
+ @client.xquery("SELECT ?", 1).first.should eql(['1'])
74
+ @client.xquery("SELECT ?+1", 1).first.should eql([2.0])
75
+ end
76
+
77
+ it "should be able to return results with symbolized keys" do
78
+ @client.xquery("SELECT 1", :symbolize_keys => true).first.keys[0].class.should eql(Symbol)
79
+ end
80
+
81
+ it "should require an open connection" do
82
+ @client.close
83
+ lambda {
84
+ @client.xquery "SELECT ?", 1
85
+ }.should raise_error(Mysql2::Error)
86
+ end
87
+ end
88
+
89
+ it "should respond to escape" do
90
+ Mysql2::Client.should respond_to(:escape)
91
+ end
92
+
93
+ if RUBY_VERSION =~ /1.9/
94
+ it "should respond to #encoding" do
95
+ @client.should respond_to(:encoding)
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,69 @@
1
+ # encoding: UTF-8
2
+ require 'spec_helper'
3
+
4
+ describe Mysql2::Error do
5
+ before(:each) do
6
+ @client = Mysql2::Client.new :encoding => "utf8"
7
+ begin
8
+ @client.query("HAHAHA")
9
+ rescue Mysql2::Error => e
10
+ @error = e
11
+ end
12
+
13
+ @client2 = Mysql2::Client.new :encoding => "big5"
14
+ begin
15
+ @client2.query("HAHAHA")
16
+ rescue Mysql2::Error => e
17
+ @error2 = e
18
+ end
19
+ end
20
+
21
+ it "should respond to #error_number" do
22
+ @error.should respond_to(:error_number)
23
+ end
24
+
25
+ it "should respond to #sql_state" do
26
+ @error.should respond_to(:sql_state)
27
+ end
28
+
29
+ # Mysql gem compatibility
30
+ it "should alias #error_number to #errno" do
31
+ @error.should respond_to(:errno)
32
+ end
33
+
34
+ it "should alias #message to #error" do
35
+ @error.should respond_to(:error)
36
+ end
37
+
38
+ if RUBY_VERSION =~ /1.9/
39
+ it "#message encoding should match the connection's encoding, or Encoding.default_internal if set" do
40
+ if Encoding.default_internal.nil?
41
+ @error.message.encoding.should eql(@client.encoding)
42
+ @error2.message.encoding.should eql(@client2.encoding)
43
+ else
44
+ @error.message.encoding.should eql(Encoding.default_internal)
45
+ @error2.message.encoding.should eql(Encoding.default_internal)
46
+ end
47
+ end
48
+
49
+ it "#error encoding should match the connection's encoding, or Encoding.default_internal if set" do
50
+ if Encoding.default_internal.nil?
51
+ @error.error.encoding.should eql(@client.encoding)
52
+ @error2.error.encoding.should eql(@client2.encoding)
53
+ else
54
+ @error.error.encoding.should eql(Encoding.default_internal)
55
+ @error2.error.encoding.should eql(Encoding.default_internal)
56
+ end
57
+ end
58
+
59
+ it "#sql_state encoding should match the connection's encoding, or Encoding.default_internal if set" do
60
+ if Encoding.default_internal.nil?
61
+ @error.sql_state.encoding.should eql(@client.encoding)
62
+ @error2.sql_state.encoding.should eql(@client2.encoding)
63
+ else
64
+ @error.sql_state.encoding.should eql(Encoding.default_internal)
65
+ @error2.sql_state.encoding.should eql(Encoding.default_internal)
66
+ end
67
+ end
68
+ end
69
+ end
data/spec/rcov.opts ADDED
@@ -0,0 +1,3 @@
1
+ --exclude spec,gem
2
+ --text-summary
3
+ --sort coverage --sort-reverse
@@ -0,0 +1,68 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'rspec'
4
+ # require 'mysql2'
5
+ require 'mysql2-cs-bind'
6
+ require 'timeout'
7
+
8
+ RSpec.configure do |config|
9
+ config.before(:all) do
10
+ client = Mysql2::Client.new :host => "localhost", :username => "root", :database => 'test'
11
+ client.query %[
12
+ CREATE TABLE IF NOT EXISTS mysql2_test (
13
+ id MEDIUMINT NOT NULL AUTO_INCREMENT,
14
+ null_test VARCHAR(10),
15
+ bit_test BIT(64),
16
+ tiny_int_test TINYINT,
17
+ bool_cast_test TINYINT(1),
18
+ small_int_test SMALLINT,
19
+ medium_int_test MEDIUMINT,
20
+ int_test INT,
21
+ big_int_test BIGINT,
22
+ float_test FLOAT(10,3),
23
+ float_zero_test FLOAT(10,3),
24
+ double_test DOUBLE(10,3),
25
+ decimal_test DECIMAL(10,3),
26
+ decimal_zero_test DECIMAL(10,3),
27
+ date_test DATE,
28
+ date_time_test DATETIME,
29
+ timestamp_test TIMESTAMP,
30
+ time_test TIME,
31
+ year_test YEAR(4),
32
+ char_test CHAR(10),
33
+ varchar_test VARCHAR(10),
34
+ binary_test BINARY(10),
35
+ varbinary_test VARBINARY(10),
36
+ tiny_blob_test TINYBLOB,
37
+ tiny_text_test TINYTEXT,
38
+ blob_test BLOB,
39
+ text_test TEXT,
40
+ medium_blob_test MEDIUMBLOB,
41
+ medium_text_test MEDIUMTEXT,
42
+ long_blob_test LONGBLOB,
43
+ long_text_test LONGTEXT,
44
+ enum_test ENUM('val1', 'val2'),
45
+ set_test SET('val1', 'val2'),
46
+ PRIMARY KEY (id)
47
+ )
48
+ ]
49
+ client.query "DELETE FROM mysql2_test;"
50
+ client.query %[
51
+ INSERT INTO mysql2_test (
52
+ null_test, bit_test, tiny_int_test, bool_cast_test, small_int_test, medium_int_test, int_test, big_int_test,
53
+ float_test, float_zero_test, double_test, decimal_test, decimal_zero_test, date_test, date_time_test, timestamp_test, time_test,
54
+ year_test, char_test, varchar_test, binary_test, varbinary_test, tiny_blob_test,
55
+ tiny_text_test, blob_test, text_test, medium_blob_test, medium_text_test,
56
+ long_blob_test, long_text_test, enum_test, set_test
57
+ )
58
+
59
+ VALUES (
60
+ NULL, b'101', 1, 1, 10, 10, 10, 10,
61
+ 10.3, 0, 10.3, 10.3, 0, '2010-4-4', '2010-4-4 11:44:00', '2010-4-4 11:44:00', '11:44:00',
62
+ 2009, "test", "test", "test", "test", "test",
63
+ "test", "test", "test", "test", "test",
64
+ "test", "test", 'val1', 'val1,val2'
65
+ )
66
+ ]
67
+ end
68
+ end
metadata ADDED
@@ -0,0 +1,157 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mysql2-cs-bind
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - TAGOMORI Satoshi
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-04-20 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: mysql2
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: mysql2
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: eventmachine
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: rake-compiler
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ~>
68
+ - !ruby/object:Gem::Version
69
+ version: 0.7.7
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ~>
76
+ - !ruby/object:Gem::Version
77
+ version: 0.7.7
78
+ - !ruby/object:Gem::Dependency
79
+ name: rake
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - '='
84
+ - !ruby/object:Gem::Version
85
+ version: 0.8.7
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - '='
92
+ - !ruby/object:Gem::Version
93
+ version: 0.8.7
94
+ - !ruby/object:Gem::Dependency
95
+ name: rspec
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ description: extension for mysql2 to add client-side variable binding, by adding method
111
+ Mysql2::Client#xquery
112
+ email:
113
+ - tagomoris@gmail.com
114
+ executables: []
115
+ extensions: []
116
+ extra_rdoc_files: []
117
+ files:
118
+ - .gitignore
119
+ - Gemfile
120
+ - MIT-LICENSE
121
+ - README.md
122
+ - Rakefile
123
+ - lib/mysql2-cs-bind.rb
124
+ - mysql2-cs-bind.gemspec
125
+ - spec/mysql2/client_spec.rb
126
+ - spec/mysql2/error_spec.rb
127
+ - spec/rcov.opts
128
+ - spec/spec_helper.rb
129
+ homepage: https://github.com/tagomoris/mysql2-cs-bind
130
+ licenses: []
131
+ post_install_message:
132
+ rdoc_options: []
133
+ require_paths:
134
+ - lib
135
+ required_ruby_version: !ruby/object:Gem::Requirement
136
+ none: false
137
+ requirements:
138
+ - - ! '>='
139
+ - !ruby/object:Gem::Version
140
+ version: '0'
141
+ required_rubygems_version: !ruby/object:Gem::Requirement
142
+ none: false
143
+ requirements:
144
+ - - ! '>='
145
+ - !ruby/object:Gem::Version
146
+ version: '0'
147
+ requirements: []
148
+ rubyforge_project:
149
+ rubygems_version: 1.8.21
150
+ signing_key:
151
+ specification_version: 3
152
+ summary: extension for mysql2 to add client-side variable binding
153
+ test_files:
154
+ - spec/mysql2/client_spec.rb
155
+ - spec/mysql2/error_spec.rb
156
+ - spec/rcov.opts
157
+ - spec/spec_helper.rb