ronin-code-sql 2.0.0 → 2.1.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bebb1935967905988d415c412fa1a88b3e8785da8ec9c22cfcd9e9a9ec4a7a34
4
- data.tar.gz: dd91249093d87d6d351fd4f4a766010e053ed780b419e5e370395e5d168a1d1f
3
+ metadata.gz: 0165dc3946e79bbbe0485338ff3c428f79f5eb28e35efc20fab1d2a0c92eb0d6
4
+ data.tar.gz: 6fc74345c7179f833eec309052ff8c8cccacbf5e98ac29267e50443f3dd2af4c
5
5
  SHA512:
6
- metadata.gz: efdbd2b72acd2d75865109d0b803c5a65681085c7fd76cef7c630da3fade71326aa982328cf0ec2dc30ca4e4929f3a52b767872405dc1584246629da1f94ccc3
7
- data.tar.gz: c8fec6e491e0cea640b18ea4be2d4ff479e679f15eaddaafbbc07b17b28fe1c8a3a32b96243237f2904850dae3397bcc8c4a3ed45b5fb3c109a0dd28a4104b3f
6
+ metadata.gz: 7bd8f7552183364ab26f237413935ca10e0772acf2d3a62b4634ada80de19a02532c22ee9aa9a41e764d4c4ccc522ce1e66dad1d7fb4e6df77879516d93ec2e8
7
+ data.tar.gz: bb5767cac1ba1fe4ae7fc68b30477f0e6e862c0fc2831fd142124eeabb1d2038f4c00148c3ac3ec599d257c9e247ca9b7248903e71e79ce1bc11d5bde2a9bc6b
@@ -12,11 +12,13 @@ jobs:
12
12
  - '3.0'
13
13
  - '3.1'
14
14
  - '3.2'
15
+ - '3.3'
16
+ - '3.4'
15
17
  - jruby
16
18
  - truffleruby
17
19
  name: Ruby ${{ matrix.ruby }}
18
20
  steps:
19
- - uses: actions/checkout@v2
21
+ - uses: actions/checkout@v4
20
22
  - name: Set up Ruby
21
23
  uses: ruby/setup-ruby@v1
22
24
  with:
@@ -26,3 +28,17 @@ jobs:
26
28
  run: bundle install --jobs 4 --retry 3
27
29
  - name: Run tests
28
30
  run: bundle exec rake test
31
+
32
+ # rubocop linting
33
+ rubocop:
34
+ runs-on: ubuntu-latest
35
+ steps:
36
+ - uses: actions/checkout@v4
37
+ - name: Set up Ruby
38
+ uses: ruby/setup-ruby@v1
39
+ with:
40
+ ruby-version: 3.0
41
+ - name: Install dependencies
42
+ run: bundle install --jobs 4 --retry 3
43
+ - name: Run rubocop
44
+ run: bundle exec rubocop --parallel
data/.rubocop.yml ADDED
@@ -0,0 +1,13 @@
1
+ AllCops:
2
+ NewCops: enable
3
+ SuggestExtensions: false
4
+ TargetRubyVersion: 3.1
5
+
6
+ inherit_gem:
7
+ rubocop-ronin: rubocop.yml
8
+
9
+ #
10
+ # ronin-code-sql specific exceptions
11
+ #
12
+ Lint/BinaryOperatorWithIdenticalOperands: { Exclude: ['spec/**/*_spec.rb'] }
13
+ Naming/MethodParameterName: { Exclude: ['lib/ronin/code/sql/functions.rb'] }
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- ruby-3.1
1
+ ruby-3.3
data/ChangeLog.md CHANGED
@@ -1,4 +1,19 @@
1
- ### 2.0.0 / 2023-XX-XX
1
+ ### 2.1.1 / 2025-02-14
2
+
3
+ * Omit parentheses when formatting SQL lists containing only one element
4
+ (ex: `order_by(1)` -> `ORDER BY 1`, not `ORDER BY (1)`).
5
+ * Use `require_relative` to improve load times.
6
+
7
+ ### 2.1.0 / 2023-06-26
8
+
9
+ * Added {Ronin::Code::SQL::Mixin}.
10
+ * Added {Ronin::Code::SQLI} as an alias for {Ronin::Code::SQL::Injection}.
11
+ * Added support for the `syntax:` and `comment:` keyword arguments to
12
+ {Ronin::Code::SQL::Statement#to_sql} and {Ronin::Code::SQL::Injection#to_sql}.
13
+ * Added {Ronin::Code::SQL::Clauses#order_by}.
14
+ * Added {Ronin::Code::SQL::Emitter#emit_comment}.
15
+
16
+ ### 2.0.0 / 2023-02-01
2
17
 
3
18
  * Require `ruby` >= 3.0.0.
4
19
  * Added [ronin-support] ~> 0.1 as a dependency.
data/Gemfile CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  source 'https://rubygems.org'
2
4
 
3
5
  gemspec
@@ -25,4 +27,6 @@ group :development do
25
27
  gem 'dead_end', require: false
26
28
  gem 'sord', require: false, platform: :mri
27
29
  gem 'stackprof', require: false, platform: :mri
30
+ gem 'rubocop', require: false, platform: :mri
31
+ gem 'rubocop-ronin', require: false, platform: :mri
28
32
  end
data/README.md CHANGED
@@ -8,7 +8,6 @@
8
8
  * [Issues](https://github.com/ronin-rb/ronin-code-sql/issues)
9
9
  * [Documentation](https://ronin-rb.dev/docs/ronin-code-sql/frames)
10
10
  * [Discord](https://discord.gg/6WAb3PsVX9) |
11
- [Twitter](https://twitter.com/ronin_rb) |
12
11
  [Mastodon](https://infosec.exchange/@ronin_rb)
13
12
 
14
13
  ## Description
@@ -61,7 +60,7 @@ string.sql_decode
61
60
  Injecting a `1=1` test into a Integer comparison:
62
61
 
63
62
  ```ruby
64
- sqli = Ronin::Code::SQL::Injection.new
63
+ sqli = Ronin::Code::SQLI.new
65
64
  sqli.or { 1 == 1 }
66
65
  puts sqli
67
66
  # 1 OR 1=1
@@ -70,7 +69,7 @@ puts sqli
70
69
  Injecting a `1=1` test into a String comparison:
71
70
 
72
71
  ```ruby
73
- sqli = Ronin::Code::SQL::Injection.new(escape: :string)
72
+ sqli = Ronin::Code::SQLI.new(escape: :string)
74
73
  sqli.or { string(1) == string(1) }
75
74
  puts sqli
76
75
  # 1' OR '1'='1
@@ -79,7 +78,7 @@ puts sqli
79
78
  Columns:
80
79
 
81
80
  ```ruby
82
- sqli = Ronin::Code::SQL::Injection.new
81
+ sqli = Ronin::Code::SQLI.new
83
82
  sqli.and { admin == 1 }
84
83
  puts sqli
85
84
  # 1 AND admin=1
@@ -88,7 +87,7 @@ puts sqli
88
87
  Clauses:
89
88
 
90
89
  ```ruby
91
- sqli = Ronin::Code::SQL::Injection.new
90
+ sqli = Ronin::Code::SQLI.new
92
91
  sqli.or { 1 == 1 }.limit(0)
93
92
  puts sqli
94
93
  # 1 OR 1=1 LIMIT 0
@@ -97,7 +96,7 @@ puts sqli
97
96
  Statements:
98
97
 
99
98
  ```ruby
100
- sqli = Ronin::Code::SQL::Injection.new
99
+ sqli = Ronin::Code::SQLI.new
101
100
  sqli.and { 1 == 0 }
102
101
  sqli.insert.into(:users).values('hacker','passw0rd','t')
103
102
  puts sqli
@@ -107,7 +106,7 @@ puts sqli
107
106
  Sub-Statements:
108
107
 
109
108
  ```ruby
110
- sqli = Ronin::Code::SQL::Injection.new
109
+ sqli = Ronin::Code::SQLI.new
111
110
  sqli.union { select(1,2,3,4,id).from(users) }
112
111
  puts sqli
113
112
  # 1 UNION SELECT (1,2,3,4,id) FROM users
@@ -116,7 +115,7 @@ puts sqli
116
115
  Test if a table exists:
117
116
 
118
117
  ```ruby
119
- sqli = Ronin::Code::SQL::Injection.new
118
+ sqli = Ronin::Code::SQLI.new
120
119
  sqli.and { select(count).from(:users) == 1 }
121
120
  puts sqli
122
121
  # 1 AND (SELECT COUNT(*) FROM users)=1
@@ -125,7 +124,7 @@ puts sqli
125
124
  Create errors by using non-existent tables:
126
125
 
127
126
  ```ruby
128
- sqli = Ronin::Code::SQL::Injection.new(escape: :string)
127
+ sqli = Ronin::Code::SQLI.new(escape: :string)
129
128
  sqli.and { non_existent_table == '1' }
130
129
  puts sqli
131
130
  # 1' AND non_existent_table='1
@@ -134,7 +133,7 @@ puts sqli
134
133
  Dumping all values of a column:
135
134
 
136
135
  ```ruby
137
- sqli = Ronin::Code::SQL::Injection.new(escape: :string)
136
+ sqli = Ronin::Code::SQLI.new(escape: :string)
138
137
  sqli.or { username.is_not(null) }.or { username == '' }
139
138
  puts sqli
140
139
  # 1' OR username IS NOT NULL OR username='
@@ -143,7 +142,7 @@ puts sqli
143
142
  Enumerate through database table names:
144
143
 
145
144
  ```ruby
146
- sqli = Ronin::Code::SQL::Injection.new
145
+ sqli = Ronin::Code::SQLI.new
147
146
  sqli.and {
148
147
  ascii(
149
148
  lower(
@@ -160,7 +159,7 @@ puts sqli
160
159
  Find user supplied tables via the `sysObjects` table:
161
160
 
162
161
  ```ruby
163
- sqli = Ronin::Code::SQL::Injection.new
162
+ sqli = Ronin::Code::SQLI.new
164
163
  sqli.union_all {
165
164
  select(1,2,3,4,5,6,name).from(sysObjects).where { xtype == 'U' }
166
165
  }
@@ -171,12 +170,21 @@ puts sqli.to_sql(terminate: true)
171
170
  Bypass filters using `/**/` instead of spaces:
172
171
 
173
172
  ```ruby
174
- sqli = Ronin::Code::SQL::Injection.new
173
+ sqli = Ronin::Code::SQLI.new
175
174
  sqli.union { select(1,2,3,4,id).from(users) }
176
175
  puts sqli.to_sql(space: '/**/')
177
176
  # 1/**/UNION/**/SELECT/**/(1,2,3,4,id)/**/FROM/**/users
178
177
  ```
179
178
 
179
+ Bypass filters using MySQL `#` comments:
180
+
181
+ ```ruby
182
+ sqli = Ronin::Code::SQLI.new
183
+ sqli.or { 1 == 1 }
184
+ puts sqli.to_sql(terminate: true, comment: '#')
185
+ # 1 OR 1=1 OR 1=1;#
186
+ ```
187
+
180
188
  ## Requirements
181
189
 
182
190
  * [Ruby] >= 3.0.0
@@ -192,7 +200,7 @@ $ gem install ronin-code-sql
192
200
 
193
201
  ronin-code-sql - A Ruby DSL for crafting SQL Injections.
194
202
 
195
- Copyright (c) 2007-2023 Hal Brodigan (postmodern.mod3 at gmail.com)
203
+ Copyright (c) 2007-2025 Hal Brodigan (postmodern.mod3 at gmail.com)
196
204
 
197
205
  ronin-code-sql is free software: you can redistribute it and/or modify
198
206
  it under the terms of the GNU Lesser General Public License as published
data/Rakefile CHANGED
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'rubygems'
2
3
 
3
4
  begin
data/gemspec.yml CHANGED
@@ -3,7 +3,7 @@ summary: A Ruby DSL for crafting SQL Injections.
3
3
  description:
4
4
  ronin-code-sql is a Ruby DSL for crafting SQL Injections.
5
5
 
6
- license: LGPL-3.0
6
+ license: LGPL-3.0-or-later
7
7
  authors: Postmodern
8
8
  email: postmodern.mod3@gmail.com
9
9
  homepage: https://github.com/ronin-rb/ronin-code-sql#readme
@@ -2,7 +2,7 @@
2
2
  #
3
3
  # ronin-code-sql - A Ruby DSL for crafting SQL Injections.
4
4
  #
5
- # Copyright (c) 2007-2023 Hal Brodigan (postmodern.mod3 at gmail.com)
5
+ # Copyright (c) 2007-2025 Hal Brodigan (postmodern.mod3 at gmail.com)
6
6
  #
7
7
  # ronin-code-sql is free software: you can redistribute it and/or modify
8
8
  # it under the terms of the GNU Lesser General Public License as published
@@ -18,8 +18,8 @@
18
18
  # along with ronin-code-sql. If not, see <https://www.gnu.org/licenses/>.
19
19
  #
20
20
 
21
- require 'ronin/code/sql/operators'
22
- require 'ronin/code/sql/emittable'
21
+ require_relative 'operators'
22
+ require_relative 'emittable'
23
23
 
24
24
  module Ronin
25
25
  module Code
@@ -29,11 +29,44 @@ module Ronin
29
29
  #
30
30
  # @api semipublic
31
31
  #
32
- class BinaryExpr < Struct.new(:left,:operator,:right)
32
+ class BinaryExpr
33
33
 
34
34
  include Operators
35
35
  include Emittable
36
36
 
37
+ # The left-hand side of the binary expression.
38
+ #
39
+ # @return [Statement, Function, BinaryExpr, Field, Literal]
40
+ attr_reader :left
41
+
42
+ # The binary expression's operator.
43
+ #
44
+ # @return [Symbol]
45
+ attr_reader :operator
46
+
47
+ # The right-hand side of the binary expression.
48
+ #
49
+ # @return [Object]
50
+ attr_reader :right
51
+
52
+ #
53
+ # Initializes the binary expression.
54
+ #
55
+ # @param [Statement, Function, BinaryExpr, Field, Literal] left
56
+ # The left-hand side of the binary expression.
57
+ #
58
+ # @param [Symbol] operator
59
+ # The binary expression's operator.
60
+ #
61
+ # @param [Object] right
62
+ # The right-hand side of the binary expression.
63
+ #
64
+ def initialize(left,operator,right)
65
+ @left = left
66
+ @operator = operator
67
+ @right = right
68
+ end
69
+
37
70
  #
38
71
  # Converts the binary expression to SQL.
39
72
  #
@@ -2,7 +2,7 @@
2
2
  #
3
3
  # ronin-code-sql - A Ruby DSL for crafting SQL Injections.
4
4
  #
5
- # Copyright (c) 2007-2023 Hal Brodigan (postmodern.mod3 at gmail.com)
5
+ # Copyright (c) 2007-2025 Hal Brodigan (postmodern.mod3 at gmail.com)
6
6
  #
7
7
  # ronin-code-sql is free software: you can redistribute it and/or modify
8
8
  # it under the terms of the GNU Lesser General Public License as published
@@ -18,12 +18,12 @@
18
18
  # along with ronin-code-sql. If not, see <https://www.gnu.org/licenses/>.
19
19
  #
20
20
 
21
- require 'ronin/code/sql/literals'
22
- require 'ronin/code/sql/fields'
23
- require 'ronin/code/sql/functions'
24
- require 'ronin/code/sql/statement'
25
- require 'ronin/code/sql/statements'
26
- require 'ronin/code/sql/emittable'
21
+ require_relative 'literals'
22
+ require_relative 'fields'
23
+ require_relative 'functions'
24
+ require_relative 'statement'
25
+ require_relative 'statements'
26
+ require_relative 'emittable'
27
27
 
28
28
  module Ronin
29
29
  module Code
@@ -33,7 +33,7 @@ module Ronin
33
33
  #
34
34
  # @api semipublic
35
35
  #
36
- class Clause < Struct.new(:keyword,:argument)
36
+ class Clause
37
37
 
38
38
  include Literals
39
39
  include Fields
@@ -41,13 +41,23 @@ module Ronin
41
41
  include Statements
42
42
  include Emittable
43
43
 
44
+ # The name of the clause.
45
+ #
46
+ # @return [Symbol]
47
+ attr_reader :keyword
48
+
49
+ # The clause's argument.
50
+ #
51
+ # @return [Object, nil]
52
+ attr_reader :argument
53
+
44
54
  #
45
55
  # Initializes the SQL clause.
46
56
  #
47
57
  # @param [Symbol] keyword
48
58
  # The name of the clause.
49
59
  #
50
- # @param [Object] argument
60
+ # @param [Object, nil] argument
51
61
  # Additional argument for the clause.
52
62
  #
53
63
  # @yield [(clause)]
@@ -58,13 +68,14 @@ module Ronin
58
68
  # Otherwise the block will be evaluated within the clause.
59
69
  #
60
70
  def initialize(keyword,argument=nil,&block)
61
- super(keyword,argument)
71
+ @keyword = keyword
72
+ @argument = argument
62
73
 
63
74
  if block
64
- self.argument = case block.arity
65
- when 0 then instance_eval(&block)
66
- else block.call(self)
67
- end
75
+ @argument = case block.arity
76
+ when 0 then instance_eval(&block)
77
+ else block.call(self)
78
+ end
68
79
  end
69
80
  end
70
81
 
@@ -2,7 +2,7 @@
2
2
  #
3
3
  # ronin-code-sql - A Ruby DSL for crafting SQL Injections.
4
4
  #
5
- # Copyright (c) 2007-2023 Hal Brodigan (postmodern.mod3 at gmail.com)
5
+ # Copyright (c) 2007-2025 Hal Brodigan (postmodern.mod3 at gmail.com)
6
6
  #
7
7
  # ronin-code-sql is free software: you can redistribute it and/or modify
8
8
  # it under the terms of the GNU Lesser General Public License as published
@@ -75,7 +75,7 @@ module Ronin
75
75
  #
76
76
  # Appends an `INTO` clause.
77
77
  #
78
- # @param [Field, Symbol] table
78
+ # @param [Field, Symbol, nil] table
79
79
  # The table to insert into.
80
80
  #
81
81
  # @return [self]
@@ -194,6 +194,20 @@ module Ronin
194
194
  clause([:GROUP, :BY],columns,&block)
195
195
  end
196
196
 
197
+ #
198
+ # Appends a `ORDER BY` clause.
199
+ #
200
+ # @param [Array<Field, Symbol>] columns
201
+ # The columns for `ORDER BY`.
202
+ #
203
+ # @return [self]
204
+ #
205
+ # @since 2.1.0
206
+ #
207
+ def order_by(*columns,&block)
208
+ clause([:ORDER, :BY],columns,&block)
209
+ end
210
+
197
211
  #
198
212
  # Appends a `HAVING` clause.
199
213
  #
@@ -231,7 +245,7 @@ module Ronin
231
245
  # Appends a `TOP` clause.
232
246
  #
233
247
  # @param [Integer] value
234
- # The number of top rows to select.
248
+ # The number of top rows to select.
235
249
  #
236
250
  # @return [self]
237
251
  #
@@ -239,18 +253,6 @@ module Ronin
239
253
  clause(:TOP,value,&block)
240
254
  end
241
255
 
242
- #
243
- # Appends a `INTO` clause.
244
- #
245
- # @param [Field, Symbol] table
246
- # The table to insert/replace into.
247
- #
248
- # @return [self]
249
- #
250
- def into(table)
251
- clause(:INTO,table)
252
- end
253
-
254
256
  #
255
257
  # Appends a `VALUES` clause.
256
258
  #
@@ -2,7 +2,7 @@
2
2
  #
3
3
  # ronin-code-sql - A Ruby DSL for crafting SQL Injections.
4
4
  #
5
- # Copyright (c) 2007-2023 Hal Brodigan (postmodern.mod3 at gmail.com)
5
+ # Copyright (c) 2007-2025 Hal Brodigan (postmodern.mod3 at gmail.com)
6
6
  #
7
7
  # ronin-code-sql is free software: you can redistribute it and/or modify
8
8
  # it under the terms of the GNU Lesser General Public License as published
@@ -18,7 +18,7 @@
18
18
  # along with ronin-code-sql. If not, see <https://www.gnu.org/licenses/>.
19
19
  #
20
20
 
21
- require 'ronin/code/sql/emitter'
21
+ require_relative 'emitter'
22
22
 
23
23
  module Ronin
24
24
  module Code
@@ -36,7 +36,7 @@ module Ronin
36
36
  # Additional keyword arguments for {Emitter#initialize}.
37
37
  #
38
38
  # @api private
39
- #
39
+ #
40
40
  def emitter(**kwargs)
41
41
  Emitter.new(**kwargs)
42
42
  end
@@ -56,6 +56,13 @@ module Ronin
56
56
  # @option kwargs [:single, :double] :quotes (:single)
57
57
  # Type of quotes to use for Strings.
58
58
  #
59
+ # @option kwargs [nil, :mysql, :postgres, :oracle, :mssql] :syntax
60
+ # Specific SQL syntax to use.
61
+ #
62
+ # @option kwargs [nil, String] :comment
63
+ # Optional String to use as the SQL comment when terminating
64
+ # injection string
65
+ #
59
66
  # @return [String]
60
67
  # The raw SQL.
61
68
  #
@@ -2,7 +2,7 @@
2
2
  #
3
3
  # ronin-code-sql - A Ruby DSL for crafting SQL Injections.
4
4
  #
5
- # Copyright (c) 2007-2023 Hal Brodigan (postmodern.mod3 at gmail.com)
5
+ # Copyright (c) 2007-2025 Hal Brodigan (postmodern.mod3 at gmail.com)
6
6
  #
7
7
  # ronin-code-sql is free software: you can redistribute it and/or modify
8
8
  # it under the terms of the GNU Lesser General Public License as published
@@ -31,14 +31,30 @@ module Ronin
31
31
  class Emitter
32
32
 
33
33
  # The case to use when emitting keywords
34
+ #
35
+ # @return [:lower, :upper, :random, nil]
34
36
  attr_reader :case
35
37
 
36
38
  # String to use for white-space
39
+ #
40
+ # @return [String]
37
41
  attr_reader :space
38
42
 
39
43
  # Type of String quotes to use
44
+ #
45
+ # @return [:single, :double]
40
46
  attr_reader :quotes
41
47
 
48
+ # Generate DB-specific code
49
+ #
50
+ # @return [nil, :mysql, :postgres, :oracle, :mssql]
51
+ attr_reader :syntax
52
+
53
+ # String to use as 'comment' or `nil` to let the emitter decide
54
+ #
55
+ # @return [String, nil]
56
+ attr_reader :comment
57
+
42
58
  #
43
59
  # Initializes the SQL Emitter.
44
60
  #
@@ -48,16 +64,24 @@ module Ronin
48
64
  # @param [:single, :double] quotes
49
65
  # Type of quotes to use for Strings.
50
66
  #
67
+ # @param [nil, :mysql, :postgres, :oracle, :mssql] syntax
68
+ # Syntax used during code-generation
69
+ #
70
+ # @param [nil, String] comment
71
+ # String to use as the comment when terminating injection string
72
+ #
51
73
  # @param [Hash{Symbol => Object}] kwargs
52
74
  # Emitter options.
53
75
  #
54
76
  # @option kwargs [:lower, :upper, :random, nil] :case
55
77
  # Case for keywords.
56
78
  #
57
- def initialize(space: ' ', quotes: :single, **kwargs)
58
- @case = kwargs[:case] # HACK: because `case` is a ruby keyword
59
- @space = space
60
- @quotes = quotes
79
+ def initialize(space: ' ', quotes: :single, syntax: nil, comment: nil, **kwargs)
80
+ @case = kwargs[:case] # HACK: because `case` is a ruby keyword
81
+ @syntax = syntax
82
+ @comment = comment
83
+ @space = space
84
+ @quotes = quotes
61
85
  end
62
86
 
63
87
  #
@@ -70,36 +94,37 @@ module Ronin
70
94
  # The raw SQL.
71
95
  #
72
96
  def emit_keyword(keyword)
73
- keyword = Array(keyword).join(@space)
97
+ string = Array(keyword).join(@space)
74
98
 
75
99
  case @case
76
- when :upper then keyword.upcase
77
- when :lower then keyword.downcase
100
+ when :upper then string.upcase
101
+ when :lower then string.downcase
78
102
  when :random
79
- keyword.tap do
80
- (keyword.length / 2).times do
81
- index = rand(keyword.length)
82
- keyword[index] = keyword[index].swapcase
103
+ string.tap do
104
+ (string.length / 2).times do
105
+ index = rand(string.length)
106
+
107
+ string[index] = string[index].swapcase
83
108
  end
84
109
  end
85
110
  else
86
- keyword
111
+ string
87
112
  end
88
113
  end
89
114
 
90
115
  #
91
116
  # Emits a SQL operator.
92
117
  #
93
- # @param [Array<Symbol>, Symbol] op
118
+ # @param [Array<Symbol>, Symbol] operator
94
119
  # The operator symbol.
95
120
  #
96
121
  # @return [String]
97
122
  # The raw SQL.
98
123
  #
99
- def emit_operator(op)
100
- case op
101
- when /^\W+$/ then op.to_s
102
- else emit_keyword(op)
124
+ def emit_operator(operator)
125
+ case operator
126
+ when /^\W+$/ then operator.to_s
127
+ else emit_keyword(operator)
103
128
  end
104
129
  end
105
130
 
@@ -132,6 +157,19 @@ module Ronin
132
157
  "1=1"
133
158
  end
134
159
 
160
+ #
161
+ # Emits a SQL comment.
162
+ #
163
+ # @return [String]
164
+ # The raw SQL.
165
+ #
166
+ # @since 2.1.0
167
+ #
168
+ def emit_comment
169
+ # Return chosen comment or default one which works everywhere
170
+ @comment || '-- '
171
+ end
172
+
135
173
  #
136
174
  # Emits a SQL Integer.
137
175
  #
@@ -200,7 +238,11 @@ module Ronin
200
238
  # The raw SQL.
201
239
  #
202
240
  def emit_list(list)
203
- '(' + list.map { |element| emit(element) }.join(',') + ')'
241
+ if list.length == 1
242
+ emit(list.first)
243
+ else
244
+ "(#{list.map { |element| emit(element) }.join(',')})"
245
+ end
204
246
  end
205
247
 
206
248
  #
@@ -250,7 +292,8 @@ module Ronin
250
292
 
251
293
  case expr
252
294
  when BinaryExpr
253
- left, right = emit_argument(expr.left), emit_argument(expr.right)
295
+ left = emit_argument(expr.left)
296
+ right = emit_argument(expr.right)
254
297
 
255
298
  case op
256
299
  when /^\W+$/ then "#{left}#{op}#{right}"
@@ -366,16 +409,16 @@ module Ronin
366
409
  sql = emit_keyword(stmt.keyword)
367
410
 
368
411
  unless stmt.argument.nil?
369
- case stmt.argument
370
- when Array
371
- sql << @space << if stmt.argument.length == 1
412
+ sql << @space << case stmt.argument
413
+ when Array
414
+ if stmt.argument.length == 1
372
415
  emit_argument(stmt.argument[0])
373
416
  else
374
417
  emit_list(stmt.argument)
375
418
  end
376
- else
377
- sql << @space << emit_argument(stmt.argument)
378
- end
419
+ else
420
+ emit_argument(stmt.argument)
421
+ end
379
422
  end
380
423
 
381
424
  unless stmt.clauses.empty?