Class: Ronin::Code::SQL::Emitter Private

Inherits:
Object
  • Object
show all
Defined in:
lib/ronin/code/sql/emitter.rb

Overview

This class is part of a private API. You should avoid using this class if possible, as it may be removed or be changed in the future.

Generates raw SQL.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(space: ' ', quotes: :single, syntax: nil, comment: nil, **kwargs) ⇒ Emitter

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Initializes the SQL Emitter.

Parameters:

  • space (String) (defaults to: ' ')

    String to use for white-space.

  • quotes (:single, :double) (defaults to: :single)

    Type of quotes to use for Strings.

  • syntax (nil, :mysql, :postgres, :oracle, :mssql) (defaults to: nil)

    Syntax used during code-generation

  • comment (nil, String) (defaults to: nil)

    String to use as the comment when terminating injection string

  • kwargs (Hash{Symbol => Object})

    Emitter options.

Options Hash (**kwargs):

  • :case (:lower, :upper, :random, nil)

    Case for keywords.



79
80
81
82
83
84
85
# File 'lib/ronin/code/sql/emitter.rb', line 79

def initialize(space: ' ', quotes: :single, syntax: nil, comment: nil, **kwargs)
  @case    = kwargs[:case] # HACK: because `case` is a ruby keyword
  @syntax  = syntax
  @comment = comment
  @space   = space
  @quotes  = quotes
end

Instance Attribute Details

#case:lower, ... (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

The case to use when emitting keywords

Returns:

  • (:lower, :upper, :random, nil)


36
37
38
# File 'lib/ronin/code/sql/emitter.rb', line 36

def case
  @case
end

#commentString? (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

String to use as 'comment' or nil to let the emitter decide

Returns:

  • (String, nil)


56
57
58
# File 'lib/ronin/code/sql/emitter.rb', line 56

def comment
  @comment
end

#quotes:single, :double (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Type of String quotes to use

Returns:

  • (:single, :double)


46
47
48
# File 'lib/ronin/code/sql/emitter.rb', line 46

def quotes
  @quotes
end

#spaceString (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

String to use for white-space

Returns:

  • (String)


41
42
43
# File 'lib/ronin/code/sql/emitter.rb', line 41

def space
  @space
end

#syntaxnil, ... (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Generate DB-specific code

Returns:

  • (nil, :mysql, :postgres, :oracle, :mssql)


51
52
53
# File 'lib/ronin/code/sql/emitter.rb', line 51

def syntax
  @syntax
end

Instance Method Details

#emit(object) ⇒ String

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Emits a SQL object.

Parameters:

  • object (#to_sql)

    The SQL object.

Returns:

  • (String)

    The raw SQL.

Raises:

  • (ArgumentError)

    Could not emit an unknown SQL object.



340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
# File 'lib/ronin/code/sql/emitter.rb', line 340

def emit(object)
  case object
  when NilClass              then emit_null
  when TrueClass             then emit_true
  when FalseClass            then emit_false
  when Integer               then emit_integer(object)
  when Float                 then emit_decimal(object)
  when String                then emit_string(object)
  when Literal               then emit(object.value)
  when Symbol                then emit_keyword(object)
  when Field                 then emit_field(object)
  when Array                 then emit_list(object)
  when Hash                  then emit_assignments(object)
  when BinaryExpr, UnaryExpr then emit_expression(object)
  when Function              then emit_function(object)
  when Clause                then emit_clause(object)
  when Statement             then emit_statement(object)
  when StatementList         then emit_statement_list(object)
  else
    if object.respond_to?(:to_sql)
      object.to_sql
    else
      raise(ArgumentError,"cannot emit #{object.class}")
    end
  end
end

#emit_argument(operand) ⇒ String

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Emits a value used in an expression.

Parameters:

  • operand (Statement, #to_sql)

    The operand to emit.

Returns:

  • (String)

    The raw SQL.

Since:

  • 1.1.0



274
275
276
277
278
279
# File 'lib/ronin/code/sql/emitter.rb', line 274

def emit_argument(operand)
  case operand
  when Statement then "(#{emit_statement(operand)})"
  else                emit(operand)
  end
end

#emit_assignments(values) ⇒ String

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Emits a list of columns and assigned values.

Parameters:

  • values (Hash{Field,Symbol => Object})

    The column names and values.

Returns:

  • (String)

    The raw SQL.



257
258
259
260
261
# File 'lib/ronin/code/sql/emitter.rb', line 257

def emit_assignments(values)
  values.map { |key,value|
    "#{emit_keyword(key)}=#{emit(value)}"
  }.join(',')
end

#emit_clause(clause) ⇒ String

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Emits a SQL Clause.

Parameters:

  • clause (Clause)

    The SQL Clause.

Returns:

  • (String)

    The raw SQL.



376
377
378
379
380
381
382
383
384
# File 'lib/ronin/code/sql/emitter.rb', line 376

def emit_clause(clause)
  sql = emit_keyword(clause.keyword)

  unless clause.argument.nil?
    sql << @space << emit_argument(clause.argument)
  end

  return sql
end

#emit_clauses(clauses) ⇒ String

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Emits multiple SQL Clauses.

Parameters:

  • clauses (Array<Clause>)

    The clauses to emit.

Returns:

  • (String)

    The emitted clauses.



395
396
397
# File 'lib/ronin/code/sql/emitter.rb', line 395

def emit_clauses(clauses)
  clauses.map { |clause| emit_clause(clause) }.join(@space)
end

#emit_commentString

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Emits a SQL comment.

Returns:

  • (String)

    The raw SQL.

Since:

  • 2.1.0



168
169
170
171
# File 'lib/ronin/code/sql/emitter.rb', line 168

def emit_comment
  # Return chosen comment or default one which works everywhere
  @comment || '-- '
end

#emit_decimal(decimal) ⇒ String

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Emits a SQL Decimal.

Parameters:

  • decimal (Float)

    The decimal.

Returns:

  • (String)

    The raw SQL.



195
196
197
# File 'lib/ronin/code/sql/emitter.rb', line 195

def emit_decimal(decimal)
  decimal.to_s
end

#emit_expression(expr) ⇒ String

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Emits a SQL expression.

Parameters:

Returns:

  • (String)

    The raw SQL.



290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
# File 'lib/ronin/code/sql/emitter.rb', line 290

def emit_expression(expr)
  op = emit_operator(expr.operator)

  case expr
  when BinaryExpr
    left  = emit_argument(expr.left)
    right = emit_argument(expr.right)

    case op
    when /^\W+$/ then "#{left}#{op}#{right}"
    else              [left, op, right].join(@space)
    end
  when UnaryExpr
    operand = emit_argument(expr.operand)

    case expr.operator
    when /^\W+$/ then "#{op}#{operand}"
    else              [op, operand].join(@space)
    end
  end
end

#emit_falseString

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Emits a false value.

Returns:

  • (String)

    The raw SQL.



146
147
148
# File 'lib/ronin/code/sql/emitter.rb', line 146

def emit_false
  "1=0"
end

#emit_field(field) ⇒ String

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Emits a SQL field.

Parameters:

  • field (Field, Symbol, String)

    The SQL field.

Returns:

  • (String)

    The raw SQL.



221
222
223
224
225
226
227
228
229
# File 'lib/ronin/code/sql/emitter.rb', line 221

def emit_field(field)
  name = emit_keyword(field.name)

  if field.parent
    name = "#{emit_field(field.parent)}.#{name}"
  end

  return name
end

#emit_function(function) ⇒ String

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Emits a SQL function.

Parameters:

  • function (Function)

    The SQL function.

Returns:

  • (String)

    The raw SQL.



321
322
323
324
325
326
# File 'lib/ronin/code/sql/emitter.rb', line 321

def emit_function(function)
  name      = emit_keyword(function.name)
  arguments = function.arguments.map { |value| emit_argument(value) }

  return "#{name}(#{arguments.join(',')})"
end

#emit_integer(int) ⇒ String

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Emits a SQL Integer.

Parameters:

  • int (Integer)

    The Integer.

Returns:

  • (String)

    The raw SQL.



182
183
184
# File 'lib/ronin/code/sql/emitter.rb', line 182

def emit_integer(int)
  int.to_s
end

#emit_keyword(keyword) ⇒ String

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Emits a SQL keyword.

Parameters:

  • keyword (Symbol, Array<Symbol>)

    The SQL keyword.

Returns:

  • (String)

    The raw SQL.



96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/ronin/code/sql/emitter.rb', line 96

def emit_keyword(keyword)
  string = Array(keyword).join(@space)

  case @case
  when :upper  then string.upcase
  when :lower  then string.downcase
  when :random
    string.tap do
      (string.length / 2).times do
        index = rand(string.length)

        string[index] = string[index].swapcase
      end
    end
  else
    string
  end
end

#emit_list(list) ⇒ String

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Emits a list of elements.

Parameters:

  • list (#map)

    The list of elements.

Returns:

  • (String)

    The raw SQL.



240
241
242
243
244
245
246
# File 'lib/ronin/code/sql/emitter.rb', line 240

def emit_list(list)
  if list.length == 1
    emit(list.first)
  else
    "(#{list.map { |element| emit(element) }.join(',')})"
  end
end

#emit_nullString

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Emits the NULL value.

Returns:

  • (String)


136
137
138
# File 'lib/ronin/code/sql/emitter.rb', line 136

def emit_null
  emit_keyword(:NULL)
end

#emit_operator(operator) ⇒ String

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Emits a SQL operator.

Parameters:

  • operator (Array<Symbol>, Symbol)

    The operator symbol.

Returns:

  • (String)

    The raw SQL.



124
125
126
127
128
129
# File 'lib/ronin/code/sql/emitter.rb', line 124

def emit_operator(operator)
  case operator
  when /^\W+$/ then operator.to_s
  else              emit_keyword(operator)
  end
end

#emit_statement(stmt) ⇒ String

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Emits a SQL Statement.

Parameters:

Returns:

  • (String)

    The raw SQL.



408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
# File 'lib/ronin/code/sql/emitter.rb', line 408

def emit_statement(stmt)
  sql = emit_keyword(stmt.keyword)

  unless stmt.argument.nil?
    sql << @space << case stmt.argument
                     when Array
                       if stmt.argument.length == 1
                         emit_argument(stmt.argument[0])
                       else
                         emit_list(stmt.argument)
                       end
                     else
                       emit_argument(stmt.argument)
                     end
  end

  unless stmt.clauses.empty?
    sql << @space << emit_clauses(stmt.clauses)
  end

  return sql
end

#emit_statement_list(list) ⇒ String

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Emits a full SQL statement list.

Parameters:

Returns:

  • (String)

    The raw SQL.



440
441
442
443
444
# File 'lib/ronin/code/sql/emitter.rb', line 440

def emit_statement_list(list)
  list.statements.map { |stmt|
    emit_statement(stmt)
  }.join(";#{@space}")
end

#emit_string(string) ⇒ String

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Emits a SQL String.

Parameters:

  • string (String)

    The String.

Returns:

  • (String)

    The raw SQL.



208
209
210
# File 'lib/ronin/code/sql/emitter.rb', line 208

def emit_string(string)
  Support::Encoding::SQL.escape(string, quotes: @quotes)
end

#emit_trueString

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Emits a true value.

Returns:

  • (String)

    The raw SQL.



156
157
158
# File 'lib/ronin/code/sql/emitter.rb', line 156

def emit_true
  "1=1"
end