ronin-code-sql 2.0.0.beta1

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.
Files changed (62) hide show
  1. checksums.yaml +7 -0
  2. data/.document +4 -0
  3. data/.editorconfig +11 -0
  4. data/.github/workflows/ruby.yml +27 -0
  5. data/.gitignore +11 -0
  6. data/.mailmap +1 -0
  7. data/.rspec +1 -0
  8. data/.ruby-version +1 -0
  9. data/.yardopts +1 -0
  10. data/COPYING.txt +165 -0
  11. data/ChangeLog.md +104 -0
  12. data/Gemfile +28 -0
  13. data/README.md +212 -0
  14. data/Rakefile +30 -0
  15. data/gemspec.yml +25 -0
  16. data/lib/ronin/code/sql/binary_expr.rb +53 -0
  17. data/lib/ronin/code/sql/clause.rb +74 -0
  18. data/lib/ronin/code/sql/clauses.rb +310 -0
  19. data/lib/ronin/code/sql/emittable.rb +88 -0
  20. data/lib/ronin/code/sql/emitter.rb +406 -0
  21. data/lib/ronin/code/sql/field.rb +110 -0
  22. data/lib/ronin/code/sql/fields.rb +82 -0
  23. data/lib/ronin/code/sql/function.rb +53 -0
  24. data/lib/ronin/code/sql/functions.rb +1265 -0
  25. data/lib/ronin/code/sql/injection.rb +168 -0
  26. data/lib/ronin/code/sql/injection_expr.rb +113 -0
  27. data/lib/ronin/code/sql/literal.rb +40 -0
  28. data/lib/ronin/code/sql/literals.rb +83 -0
  29. data/lib/ronin/code/sql/operators.rb +384 -0
  30. data/lib/ronin/code/sql/statement.rb +72 -0
  31. data/lib/ronin/code/sql/statement_list.rb +112 -0
  32. data/lib/ronin/code/sql/statements.rb +117 -0
  33. data/lib/ronin/code/sql/unary_expr.rb +38 -0
  34. data/lib/ronin/code/sql/version.rb +28 -0
  35. data/lib/ronin/code/sql.rb +96 -0
  36. data/ronin-code-sql.gemspec +62 -0
  37. data/spec/spec_helper.rb +3 -0
  38. data/spec/sql/binary_expr_examples.rb +25 -0
  39. data/spec/sql/binary_expr_spec.rb +5 -0
  40. data/spec/sql/clause_examples.rb +43 -0
  41. data/spec/sql/clause_spec.rb +31 -0
  42. data/spec/sql/clauses_spec.rb +47 -0
  43. data/spec/sql/emittable_spec.rb +41 -0
  44. data/spec/sql/emitter_spec.rb +533 -0
  45. data/spec/sql/field_spec.rb +103 -0
  46. data/spec/sql/fields_spec.rb +40 -0
  47. data/spec/sql/function_examples.rb +30 -0
  48. data/spec/sql/function_spec.rb +25 -0
  49. data/spec/sql/functions_spec.rb +113 -0
  50. data/spec/sql/injection_expr_spec.rb +98 -0
  51. data/spec/sql/injection_spec.rb +172 -0
  52. data/spec/sql/literal_spec.rb +5 -0
  53. data/spec/sql/literals_spec.rb +46 -0
  54. data/spec/sql/operators_spec.rb +44 -0
  55. data/spec/sql/statement_examples.rb +39 -0
  56. data/spec/sql/statement_list_spec.rb +48 -0
  57. data/spec/sql/statement_spec.rb +38 -0
  58. data/spec/sql/statements_spec.rb +22 -0
  59. data/spec/sql/unary_expr_examples.rb +20 -0
  60. data/spec/sql/unary_expr_spec.rb +5 -0
  61. data/spec/sql_spec.rb +18 -0
  62. metadata +157 -0
@@ -0,0 +1,384 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ # ronin-code-sql - A Ruby DSL for crafting SQL Injections.
4
+ #
5
+ # Copyright (c) 2007-2022 Hal Brodigan (postmodern.mod3 at gmail.com)
6
+ #
7
+ # ronin-code-sql is free software: you can redistribute it and/or modify
8
+ # it under the terms of the GNU Lesser General Public License as published
9
+ # by the Free Software Foundation, either version 3 of the License, or
10
+ # (at your option) any later version.
11
+ #
12
+ # ronin-code-sql is distributed in the hope that it will be useful,
13
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ # GNU Lesser General Public License for more details.
16
+ #
17
+ # You should have received a copy of the GNU Lesser General Public License
18
+ # along with ronin-code-sql. If not, see <https://www.gnu.org/licenses/>.
19
+ #
20
+
21
+ module Ronin
22
+ module Code
23
+ module SQL
24
+ #
25
+ # Methods for creating SQL expressions.
26
+ #
27
+ # @api public
28
+ #
29
+ # @see http://sqlite.org/lang_expr.html
30
+ #
31
+ module Operators
32
+ #
33
+ # Multiplication.
34
+ #
35
+ # @param [Object] other
36
+ #
37
+ # @return [BinaryExpr]
38
+ # The new binary expression.
39
+ #
40
+ def *(other)
41
+ BinaryExpr.new(self,:*,other)
42
+ end
43
+
44
+ #
45
+ # Division.
46
+ #
47
+ # @param [Object] other
48
+ #
49
+ # @return [BinaryExpr]
50
+ # The new binary expression.
51
+ #
52
+ def /(other)
53
+ BinaryExpr.new(self,:/,other)
54
+ end
55
+
56
+ #
57
+ # Modulus.
58
+ #
59
+ # @param [Object] other
60
+ #
61
+ # @return [BinaryExpr]
62
+ # The new binary expression.
63
+ #
64
+ def %(other)
65
+ BinaryExpr.new(self,:%,other)
66
+ end
67
+
68
+ #
69
+ # Addition.
70
+ #
71
+ # @param [Object] other
72
+ #
73
+ # @return [BinaryExpr]
74
+ # The new binary expression.
75
+ #
76
+ def +(other)
77
+ BinaryExpr.new(self,:+,other)
78
+ end
79
+
80
+ #
81
+ # Subtraction.
82
+ #
83
+ # @param [Object] other
84
+ #
85
+ # @return [BinaryExpr]
86
+ # The new binary expression.
87
+ #
88
+ def -(other)
89
+ BinaryExpr.new(self,:-,other)
90
+ end
91
+
92
+ #
93
+ # Bit-wise left shift.
94
+ #
95
+ # @param [Object] other
96
+ #
97
+ # @return [BinaryExpr]
98
+ # The new binary expression.
99
+ #
100
+ def <<(other)
101
+ BinaryExpr.new(self,:<<,other)
102
+ end
103
+
104
+ #
105
+ # Bit-wise right shift.
106
+ #
107
+ # @param [Object] other
108
+ #
109
+ # @return [BinaryExpr]
110
+ # The new binary expression.
111
+ #
112
+ def >>(other)
113
+ BinaryExpr.new(self,:>>,other)
114
+ end
115
+
116
+ #
117
+ # Bit-wise `AND`.
118
+ #
119
+ # @param [Object] other
120
+ #
121
+ # @return [BinaryExpr]
122
+ # The new binary expression.
123
+ #
124
+ def &(other)
125
+ BinaryExpr.new(self,:&,other)
126
+ end
127
+
128
+ #
129
+ # Bit-wise `OR`.
130
+ #
131
+ # @param [Object] other
132
+ #
133
+ # @return [BinaryExpr]
134
+ # The new binary expression.
135
+ #
136
+ def |(other)
137
+ BinaryExpr.new(self,:|,other)
138
+ end
139
+
140
+ #
141
+ # Less than.
142
+ #
143
+ # @param [Object] other
144
+ #
145
+ # @return [BinaryExpr]
146
+ # The new binary expression.
147
+ #
148
+ def <(other)
149
+ BinaryExpr.new(self,:<,other)
150
+ end
151
+
152
+ #
153
+ # Less than or equal to.
154
+ #
155
+ # @param [Object] other
156
+ #
157
+ # @return [BinaryExpr]
158
+ # The new binary expression.
159
+ #
160
+ def <=(other)
161
+ BinaryExpr.new(self,:<=,other)
162
+ end
163
+
164
+ #
165
+ # Greater than.
166
+ #
167
+ # @param [Object] other
168
+ #
169
+ # @return [BinaryExpr]
170
+ # The new binary expression.
171
+ #
172
+ def >(other)
173
+ BinaryExpr.new(self,:>,other)
174
+ end
175
+
176
+ #
177
+ # Greater than or equal to.
178
+ #
179
+ # @param [Object] other
180
+ #
181
+ # @return [BinaryExpr]
182
+ # The new binary expression.
183
+ #
184
+ def >=(other)
185
+ BinaryExpr.new(self,:>=,other)
186
+ end
187
+
188
+ #
189
+ # Equal to.
190
+ #
191
+ # @param [Object] other
192
+ #
193
+ # @return [BinaryExpr]
194
+ # The new binary expression.
195
+ #
196
+ def ==(other)
197
+ BinaryExpr.new(self,:"=",other)
198
+ end
199
+
200
+ #
201
+ # Not equal to.
202
+ #
203
+ # @param [Object] other
204
+ #
205
+ # @return [BinaryExpr]
206
+ # The new binary expression.
207
+ #
208
+ def !=(other)
209
+ BinaryExpr.new(self,:!=,other)
210
+ end
211
+
212
+ #
213
+ # Alias.
214
+ #
215
+ # @param [Symbol] name
216
+ #
217
+ # @return [BinaryExpr]
218
+ # The new binary expression.
219
+ #
220
+ def as(name)
221
+ BinaryExpr.new(self,:AS,name)
222
+ end
223
+
224
+ #
225
+ # `IS` comparison.
226
+ #
227
+ # @param [Object] other
228
+ #
229
+ # @return [BinaryExpr]
230
+ # The new binary expression.
231
+ #
232
+ def is(other)
233
+ BinaryExpr.new(self,:IS,other)
234
+ end
235
+
236
+ #
237
+ # `IS NOT` comparison.
238
+ #
239
+ # @param [Object] other
240
+ #
241
+ # @return [BinaryExpr]
242
+ # The new binary expression.
243
+ #
244
+ def is_not(other)
245
+ BinaryExpr.new(self,[:IS, :NOT],other)
246
+ end
247
+
248
+ #
249
+ # `LIKE` comparison.
250
+ #
251
+ # @param [Object] other
252
+ #
253
+ # @return [BinaryExpr]
254
+ # The new binary expression.
255
+ #
256
+ def like(other)
257
+ BinaryExpr.new(self,:LIKE,other)
258
+ end
259
+
260
+ #
261
+ # `GLOB` comparison.
262
+ #
263
+ # @param [Object] other
264
+ #
265
+ # @return [BinaryExpr]
266
+ # The new binary expression.
267
+ #
268
+ def glob(other)
269
+ BinaryExpr.new(self,:GLOB,other)
270
+ end
271
+
272
+ #
273
+ # `MATCH` comparison.
274
+ #
275
+ # @param [Object] other
276
+ #
277
+ # @return [BinaryExpr]
278
+ # The new binary expression.
279
+ #
280
+ def match(other)
281
+ BinaryExpr.new(self,:MATCH,other)
282
+ end
283
+
284
+ #
285
+ # `REGEXP` comparison.
286
+ #
287
+ # @param [Object] other
288
+ #
289
+ # @return [BinaryExpr]
290
+ # The new binary expression.
291
+ #
292
+ def regexp(other)
293
+ BinaryExpr.new(self,:REGEXP,other)
294
+ end
295
+
296
+ #
297
+ # `REGEXP` comparison.
298
+ #
299
+ # @param [Object] other
300
+ #
301
+ # @return [BinaryExpr]
302
+ # The new binary expression.
303
+ #
304
+ def in(other)
305
+ BinaryExpr.new(self,:IN,other)
306
+ end
307
+
308
+ #
309
+ # Unary minus.
310
+ #
311
+ # @return [UnaryExpr]
312
+ # The new binary expression.
313
+ #
314
+ def -@
315
+ UnaryExpr.new(:-,self)
316
+ end
317
+
318
+ #
319
+ # Unary plus.
320
+ #
321
+ # @return [UnaryExpr]
322
+ # The new binary expression.
323
+ #
324
+ def +@
325
+ UnaryExpr.new(:+,self)
326
+ end
327
+
328
+ #
329
+ # Bit-wise negate.
330
+ #
331
+ # @return [UnaryExpr]
332
+ # The new binary expression.
333
+ #
334
+ def ~
335
+ UnaryExpr.new(:~,self)
336
+ end
337
+
338
+ #
339
+ # Logical negate.
340
+ #
341
+ # @return [UnaryExpr]
342
+ # The new binary expression.
343
+ #
344
+ def !
345
+ UnaryExpr.new(:!,self)
346
+ end
347
+
348
+ #
349
+ # Logical `NOT`.
350
+ #
351
+ # @return [UnaryExpr]
352
+ # The new binary expression.
353
+ #
354
+ def not
355
+ UnaryExpr.new(:NOT,self)
356
+ end
357
+
358
+ #
359
+ # `AND`.
360
+ #
361
+ # @param [Object] other
362
+ #
363
+ # @return [BinaryExpr]
364
+ # The new binary expression.
365
+ #
366
+ def and(other)
367
+ BinaryExpr.new(self,:AND,other)
368
+ end
369
+
370
+ #
371
+ # `OR`.
372
+ #
373
+ # @param [Object] other
374
+ #
375
+ # @return [BinaryExpr]
376
+ # The new binary expression.
377
+ #
378
+ def or(other)
379
+ BinaryExpr.new(self,:OR,other)
380
+ end
381
+ end
382
+ end
383
+ end
384
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ # ronin-code-sql - A Ruby DSL for crafting SQL Injections.
4
+ #
5
+ # Copyright (c) 2007-2022 Hal Brodigan (postmodern.mod3 at gmail.com)
6
+ #
7
+ # ronin-code-sql is free software: you can redistribute it and/or modify
8
+ # it under the terms of the GNU Lesser General Public License as published
9
+ # by the Free Software Foundation, either version 3 of the License, or
10
+ # (at your option) any later version.
11
+ #
12
+ # ronin-code-sql is distributed in the hope that it will be useful,
13
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ # GNU Lesser General Public License for more details.
16
+ #
17
+ # You should have received a copy of the GNU Lesser General Public License
18
+ # along with ronin-code-sql. If not, see <https://www.gnu.org/licenses/>.
19
+ #
20
+
21
+ require 'ronin/code/sql/literals'
22
+ require 'ronin/code/sql/clause'
23
+ require 'ronin/code/sql/clauses'
24
+ require 'ronin/code/sql/operators'
25
+ require 'ronin/code/sql/emittable'
26
+
27
+ module Ronin
28
+ module Code
29
+ module SQL
30
+ #
31
+ # Represents a SQL Statement.
32
+ #
33
+ # @api semipublic
34
+ #
35
+ class Statement < Struct.new(:keyword,:argument)
36
+
37
+ include Literals
38
+ include Operators
39
+ include Clauses
40
+ include Emittable
41
+
42
+ #
43
+ # Initializes a new SQL statement.
44
+ #
45
+ # @param [Symbol, Array<Symbol>] keyword
46
+ # Name of the statement.
47
+ #
48
+ # @param [Object] argument
49
+ # Additional argument for the statement.
50
+ #
51
+ # @yield [(statement)]
52
+ # If a block is given, it will be called.
53
+ #
54
+ # @yieldparam [Statement] statement
55
+ # If the block accepts an argument, it will be passed the new statement.
56
+ # Otherwise the block will be evaluated within the statement.
57
+ #
58
+ def initialize(keyword,argument=nil,&block)
59
+ super(keyword,argument)
60
+
61
+ if block
62
+ case block.arity
63
+ when 0 then instance_eval(&block)
64
+ else block.call(self)
65
+ end
66
+ end
67
+ end
68
+
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,112 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ # ronin-code-sql - A Ruby DSL for crafting SQL Injections.
4
+ #
5
+ # Copyright (c) 2007-2022 Hal Brodigan (postmodern.mod3 at gmail.com)
6
+ #
7
+ # ronin-code-sql is free software: you can redistribute it and/or modify
8
+ # it under the terms of the GNU Lesser General Public License as published
9
+ # by the Free Software Foundation, either version 3 of the License, or
10
+ # (at your option) any later version.
11
+ #
12
+ # ronin-code-sql is distributed in the hope that it will be useful,
13
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ # GNU Lesser General Public License for more details.
16
+ #
17
+ # You should have received a copy of the GNU Lesser General Public License
18
+ # along with ronin-code-sql. If not, see <https://www.gnu.org/licenses/>.
19
+ #
20
+
21
+ require 'ronin/code/sql/field'
22
+ require 'ronin/code/sql/fields'
23
+ require 'ronin/code/sql/unary_expr'
24
+ require 'ronin/code/sql/binary_expr'
25
+ require 'ronin/code/sql/functions'
26
+ require 'ronin/code/sql/statement'
27
+ require 'ronin/code/sql/statements'
28
+ require 'ronin/code/sql/emittable'
29
+
30
+ module Ronin
31
+ module Code
32
+ module SQL
33
+ #
34
+ # Represents a list of SQL {Statements Statement}.
35
+ #
36
+ # @api public
37
+ #
38
+ class StatementList
39
+
40
+ include Fields
41
+ include Functions
42
+ include Statements
43
+ include Emittable
44
+
45
+ # The list of statements
46
+ attr_reader :statements
47
+
48
+ #
49
+ # Initializes a new SQL statement list.
50
+ #
51
+ # @yield [(statements)]
52
+ # If a block is given, it will be evaluated within the statement list.
53
+ # If the block accepts an argument, the block will be called with the
54
+ # new statement list.
55
+ #
56
+ # @yieldparam [StatementList] statements
57
+ # The new statement list.
58
+ #
59
+ def initialize(&block)
60
+ @statements = []
61
+
62
+ if block
63
+ case block.arity
64
+ when 0 then instance_eval(&block)
65
+ else block.call(self)
66
+ end
67
+ end
68
+ end
69
+
70
+ #
71
+ # Appends a statement.
72
+ #
73
+ # @param [Statement] statement
74
+ # The SQL statement.
75
+ #
76
+ # @return [self]
77
+ #
78
+ def <<(statement)
79
+ @statements << statement
80
+ return self
81
+ end
82
+
83
+ #
84
+ # Appends an arbitrary statement.
85
+ #
86
+ # @param [Symbol] keyword
87
+ # Name of the statement.
88
+ #
89
+ # @param [Object] argument
90
+ # Additional argument for the statement.
91
+ #
92
+ # @yield [(statement)]
93
+ # If a block is given, it will be called.
94
+ #
95
+ # @yieldparam [Statement] statement
96
+ # If the block accepts an argument, it will be passed the new statement.
97
+ # Otherwise the block will be evaluated within the statement.
98
+ #
99
+ # @return [Statement]
100
+ # The newly created statement.
101
+ #
102
+ def statement(keyword,argument=nil,&block)
103
+ new_statement = super
104
+
105
+ self << new_statement
106
+ return new_statement
107
+ end
108
+
109
+ end
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,117 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ # ronin-code-sql - A Ruby DSL for crafting SQL Injections.
4
+ #
5
+ # Copyright (c) 2007-2022 Hal Brodigan (postmodern.mod3 at gmail.com)
6
+ #
7
+ # ronin-code-sql is free software: you can redistribute it and/or modify
8
+ # it under the terms of the GNU Lesser General Public License as published
9
+ # by the Free Software Foundation, either version 3 of the License, or
10
+ # (at your option) any later version.
11
+ #
12
+ # ronin-code-sql is distributed in the hope that it will be useful,
13
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ # GNU Lesser General Public License for more details.
16
+ #
17
+ # You should have received a copy of the GNU Lesser General Public License
18
+ # along with ronin-code-sql. If not, see <https://www.gnu.org/licenses/>.
19
+ #
20
+
21
+ module Ronin
22
+ module Code
23
+ module SQL
24
+ #
25
+ # Methods for creating common SQL {Statement Statements}.
26
+ #
27
+ # @api public
28
+ #
29
+ module Statements
30
+ #
31
+ # Creates an arbitrary statement.
32
+ #
33
+ # @param [Symbol] keyword
34
+ # Name of the statement.
35
+ #
36
+ # @param [Object] argument
37
+ # Additional argument for the statement.
38
+ #
39
+ # @yield [(statement)]
40
+ # If a block is given, it will be called.
41
+ #
42
+ # @yieldparam [Statement] statement
43
+ # If the block accepts an argument, it will be passed the new statement.
44
+ # Otherwise the block will be evaluated within the statement.
45
+ #
46
+ # @return [Statement]
47
+ # The new statement.
48
+ #
49
+ def statement(keyword,argument=nil,&block)
50
+ Statement.new(keyword,argument,&block)
51
+ end
52
+
53
+ #
54
+ # Creates a new `SELECT` statement.
55
+ #
56
+ # @param [Array<Field, Symbol>] columns
57
+ # The columns to select.
58
+ #
59
+ # @return [Statement]
60
+ # The new statement.
61
+ #
62
+ def select(*columns,&block)
63
+ statement(:SELECT,columns,&block)
64
+ end
65
+
66
+ #
67
+ # Creates a new `INSERT` statement.
68
+ #
69
+ # @return [Statement]
70
+ # The new statement.
71
+ #
72
+ def insert(&block)
73
+ statement(:INSERT,&block)
74
+ end
75
+
76
+ #
77
+ # Creates a new `UPDATE` statement.
78
+ #
79
+ # @param [Field, Symbol] table
80
+ # The table to update.
81
+ #
82
+ # @return [Statement]
83
+ # The new statement.
84
+ #
85
+ def update(table,&block)
86
+ statement(:UPDATE,table,&block)
87
+ end
88
+
89
+ #
90
+ # Creates a new `DELETE` statement.
91
+ #
92
+ # @param [Field, Symbol] table
93
+ # The table to delete from.
94
+ #
95
+ # @return [Statement]
96
+ # The new statement.
97
+ #
98
+ def delete(table,&block)
99
+ statement([:DELETE, :FROM],table,&block)
100
+ end
101
+
102
+ #
103
+ # Creates a new `DROP TABLE` statement.
104
+ #
105
+ # @param [Field, Symbol] table
106
+ # The table to drop.
107
+ #
108
+ # @return [Statement]
109
+ # The new statement.
110
+ #
111
+ def drop_table(table,&block)
112
+ statement([:DROP, :TABLE],table,&block)
113
+ end
114
+ end
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ # ronin-code-sql - A Ruby DSL for crafting SQL Injections.
4
+ #
5
+ # Copyright (c) 2007-2022 Hal Brodigan (postmodern.mod3 at gmail.com)
6
+ #
7
+ # ronin-code-sql is free software: you can redistribute it and/or modify
8
+ # it under the terms of the GNU Lesser General Public License as published
9
+ # by the Free Software Foundation, either version 3 of the License, or
10
+ # (at your option) any later version.
11
+ #
12
+ # ronin-code-sql is distributed in the hope that it will be useful,
13
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ # GNU Lesser General Public License for more details.
16
+ #
17
+ # You should have received a copy of the GNU Lesser General Public License
18
+ # along with ronin-code-sql. If not, see <https://www.gnu.org/licenses/>.
19
+ #
20
+
21
+ require 'ronin/code/sql/emittable'
22
+
23
+ module Ronin
24
+ module Code
25
+ module SQL
26
+ #
27
+ # Represents a unary expression in SQL.
28
+ #
29
+ # @api semipublic
30
+ #
31
+ class UnaryExpr < Struct.new(:operator,:operand)
32
+
33
+ include Emittable
34
+
35
+ end
36
+ end
37
+ end
38
+ end