File: sql_comments.rb

package info (click to toggle)
ruby-sequel 5.41.0-1
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 9,548 kB
  • sloc: ruby: 104,241; makefile: 3
file content (96 lines) | stat: -rw-r--r-- 3,120 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# frozen-string-literal: true
#
# The sql_comments extension adds Dataset#comment to the datasets,
# allowing you to set SQL comments in the resulting query.  These
# comments are appended to the end of the SQL query:
#
#   ds = DB[:table].comment("Some Comment").all
#   # SELECT * FROM table -- Some Comment
#   #
#
# As you can see, this uses single line SQL comments (--) suffixed
# by a newline.  This plugin transforms all consecutive whitespace
# in the comment to a single string:
#
#   ds = DB[:table].comment("Some\r\nComment     Here").all
#   # SELECT * FROM table -- Some Comment Here
#   #
#
# The reason for the prefixing and suffixing by newlines is to
# work correctly when used in subqueries:
#
#   ds = DB[:table].comment("Some\r\nComment     Here")
#   ds.where(id: ds).all
#   # SELECT * FROM table WHERE (id IN (SELECT * FROM table -- Some Comment Here
#   # )) -- Some Comment Here
#   #
#
# In addition to working on SELECT queries, it also works when
# inserting, updating, and deleting.
#
# Due to the use of single line SQL comments and converting all
# whitespace to spaces, this should correctly handle even
# malicious input.  However, it would be unwise to rely on that,
# you should ensure that the argument given
# to Dataset#comment is not derived from user input.
#
# You can load this extension into specific datasets:
#
#   ds = DB[:table]
#   ds = ds.extension(:sql_comments)
#
# Or you can load it into all of a database's datasets, which
# is probably the desired behavior if you are using this extension:
#
#   DB.extension(:sql_comments)
#
# Note that Microsoft Access does not support inline comments,
# and attempting to use comments on it will result in SQL syntax
# errors.
#
# Related module: Sequel::SQLComments

#
module Sequel
  module SQLComments
    # Return a modified copy of the dataset that will use the given comment.
    # To uncomment a commented dataset, pass nil as the argument.
    def comment(comment)
      clone(:comment=>(format_sql_comment(comment) if comment))
    end

    %w'select insert update delete'.each do |type|
      define_method(:"#{type}_sql") do |*a|
        sql = super(*a)
        if comment = @opts[:comment]
          # This assumes that the comment stored in the dataset has
          # already been formatted. If not, this could result in SQL
          # injection.
          #
          # Additionally, due to the use of an SQL comment, if any
          # SQL is appened to the query after the comment is added,
          # it will become part of the comment unless it is preceded
          # by a newline.
          if sql.frozen?
            sql += comment
            sql.freeze
          else
            sql << comment
          end
        end
        sql
      end
    end

    private

    # Format the comment.  For maximum compatibility, this uses a
    # single line SQL comment, and converts all consecutive whitespace
    # in the comment to a single space.
    def format_sql_comment(comment)
      " -- #{comment.to_s.gsub(/\s+/, ' ')}\n"
    end
  end

  Dataset.register_extension(:sql_comments, SQLComments)
end