akitaonrails-activerecord-sqlserver-adapter 1.1.0 → 1.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.
@@ -0,0 +1,158 @@
1
+ class ColumnInfo < Hash
2
+
3
+ # Creates and returns a ColumnInfo object. This represents metadata for
4
+ # columns within a given table, such as the data type, whether or not the
5
+ # the column is a primary key, etc.
6
+ #
7
+ # ColumnInfo is a subclass of Hash.
8
+ #
9
+ def initialize(hash=nil)
10
+ self.update(hash) if hash
11
+ end
12
+
13
+ # Returns the column's name.
14
+ def name
15
+ self['name']
16
+ end
17
+
18
+ # Sets the column's name.
19
+ def name=(val)
20
+ self['name'] = val
21
+ end
22
+
23
+ # Returns a portable integer representation of the column's type. Here are
24
+ # the constant names (under DBI) and their respective values:
25
+ #
26
+ # SQL_CHAR = 1
27
+ # SQL_NUMERIC = 2
28
+ # SQL_DECIMAL = 3
29
+ # SQL_INTEGER = 4
30
+ # SQL_SMALLINT = 5
31
+ # SQL_FLOAT = 6
32
+ # SQL_REAL = 7
33
+ # SQL_DOUBLE = 8
34
+ # SQL_DATE = 9
35
+ # SQL_TIME = 10
36
+ # SQL_TIMESTAMP = 11
37
+ # SQL_VARCHAR = 12
38
+ #
39
+ # SQL_LONGVARCHAR = -1
40
+ # SQL_BINARY = -2
41
+ # SQL_VARBINARY = -3
42
+ # SQL_LONGVARBINARY = -4
43
+ # SQL_BIGINT = -5
44
+ # SQL_BIT = -7
45
+ # SQL_TINYINT = -6
46
+ #
47
+ def sql_type
48
+ self['sql_type']
49
+ end
50
+
51
+ # Sets the integer representation for the column's type.
52
+ def sql_type=(val)
53
+ self['sql_type'] = val
54
+ end
55
+
56
+ # A string representation of the column's type, e.g. 'date'.
57
+ def type_name
58
+ self['type_name']
59
+ end
60
+
61
+ # Sets the representation for the column's type.
62
+ def type_name=(val)
63
+ self['type_name'] = val
64
+ end
65
+
66
+ # Returns the precision, i.e. number of bytes or digits.
67
+ def precision
68
+ self['precision']
69
+ end
70
+
71
+ # Sets the precision, i.e. number of bytes or digits.
72
+ def precision=(val)
73
+ self['precision'] = val
74
+ end
75
+
76
+ # Returns the number of digits from right.
77
+ def scale
78
+ self['scale']
79
+ end
80
+
81
+ # Sets the number of digits from right.
82
+ def scale=(val)
83
+ self['scale'] = val
84
+ end
85
+
86
+ # Returns the default value for the column, or nil if not set.
87
+ def default
88
+ self['default']
89
+ end
90
+
91
+ # Sets the default value for the column.
92
+ def default=(val)
93
+ self['default'] = val
94
+ end
95
+
96
+ # Returns whether or not the column is may contain a NULL.
97
+ def nullable
98
+ self['nullable']
99
+ end
100
+
101
+ # Sets whether or not the column may contain a NULL.
102
+ def nullable=(val)
103
+ self['nullable'] = val
104
+ end
105
+
106
+ # Returns whether or not the column is indexed.
107
+ def indexed
108
+ self['indexed']
109
+ end
110
+
111
+ # Sets whether or not the column is indexed.
112
+ def indexed=(val)
113
+ self['indexed'] = 'val'
114
+ end
115
+
116
+ # Returns whether or not the column is a primary key.
117
+ def primary
118
+ self['primary']
119
+ end
120
+
121
+ # Sets whether or not the column is a primary key.
122
+ def primary=(val)
123
+ self['primary'] = val
124
+ end
125
+
126
+ # Returns whether or not data in the column must be unique.
127
+ def unique
128
+ self['unique']
129
+ end
130
+
131
+ # Sets whether or not data in the column must be unique.
132
+ def unique=(val)
133
+ self['unique'] = val
134
+ end
135
+
136
+ # Aliases
137
+ alias nullable? nullable
138
+ alias is_nullable? nullable
139
+
140
+ alias indexed? indexed
141
+ alias is_indexed? indexed
142
+
143
+ alias primary? primary
144
+ alias is_primary? primary
145
+
146
+ alias unique? unique
147
+ alias is_unique unique
148
+
149
+ alias size precision
150
+ alias size= precision=
151
+ alias length precision
152
+ alias length= precision=
153
+
154
+ alias decimal_digits scale
155
+ alias decimal_digits= scale=
156
+ end
157
+
158
+
@@ -0,0 +1,205 @@
1
+ require "delegate"
2
+
3
+ # The DBI::Row class is a delegate of Array, rather than a subclass, because
4
+ # there are times when it should act like an Array, and others when it should
5
+ # act like a Hash (and still others where it should act like String, Regexp,
6
+ # etc). It also needs to store metadata about the row, such as
7
+ # column data type and index information, that users can then access.
8
+ #
9
+ module DBI
10
+ class Row < DelegateClass(Array)
11
+ attr_reader :column_names
12
+
13
+ # DBI::Row.new(columns, size_or_array=nil)
14
+ #
15
+ # Returns a new DBI::Row object using +columns+. The +size_or_array+
16
+ # argument may either be an Integer or an Array. If it is not provided,
17
+ # it defaults to the length of +columns+.
18
+ #
19
+ # DBI::Row is a delegate of the Array class, so all of the Array
20
+ # instance methods are available to your DBI::Row object (keeping in
21
+ # mind that initialize, [], and []= have been explicitly overridden).
22
+ #
23
+ def initialize(columns, size_or_array=nil)
24
+ size_or_array ||= columns.size
25
+
26
+ case size_or_array
27
+ when Integer
28
+ @arr = Array.new(size_or_array)
29
+ when Array
30
+ @arr = size_or_array
31
+ else
32
+ raise TypeError, "parameter must be either Integer or Array"
33
+ end
34
+
35
+ # The '@column_map' is used to map column names to integer values so
36
+ # that users can reference row values by name or number.
37
+
38
+ @column_map = {}
39
+ @column_names = columns
40
+ columns.each_with_index { |c,i| @column_map[c] = i }
41
+ super(@arr)
42
+ end
43
+
44
+ # Replaces the contents of @arr with +new_values+
45
+ def set_values(new_values)
46
+ @arr.replace(new_values)
47
+ end
48
+
49
+ # Yields a column value by name (rather than index), along with the
50
+ # column name itself.
51
+ def each_with_name
52
+ @arr.each_with_index do |v, i|
53
+ yield v, @column_names[i]
54
+ end
55
+ end
56
+
57
+ # Returns the Row object as a hash
58
+ def to_h
59
+ hash = {}
60
+ each_with_name{ |v, n| hash[n] = v}
61
+ hash
62
+ end
63
+
64
+ # Create a new row with 'new_values', reusing the field name hash.
65
+ def clone_with(new_values)
66
+ Row.new(@column_names, new_values)
67
+ end
68
+
69
+ alias field_names column_names
70
+
71
+ # Retrieve a value by index (rather than name).
72
+ #
73
+ # Deprecated. Since Row delegates to Array, just use Row#at.
74
+ def by_index(index)
75
+ @arr[index]
76
+ end
77
+
78
+ # Value of the field named +field_name+ or nil if not found.
79
+ def by_field(field_name)
80
+ begin
81
+ @arr[@column_map[field_name.to_s]]
82
+ rescue TypeError
83
+ nil
84
+ end
85
+ end
86
+
87
+ # Row#[]
88
+ #
89
+ # row[int]
90
+ # row[array]
91
+ # row[regexp]
92
+ # row[arg, arg]
93
+ # row[arg, arg, ...]
94
+ #
95
+ # Sample: Row.new(["first","last","age"], ["Daniel", "Berger", "36"])
96
+ #
97
+ # Retrieves row elements. Exactly what it retrieves depends on the
98
+ # kind and number of arguments used.
99
+ #
100
+ # Zero arguments will raise an ArgumentError.
101
+ #
102
+ # One argument will return a single result. This can be a String,
103
+ # Symbol, Integer, Range or Regexp and the appropriate result will
104
+ # be returned. Strings, Symbols and Regexps act like hash lookups,
105
+ # while Integers and Ranges act like Array index lookups.
106
+ #
107
+ # Two arguments will act like the second form of Array#[], i.e it takes
108
+ # two integers, with the first number the starting point and the second
109
+ # number the length, and returns an array of values.
110
+ #
111
+ # If three or more arguments are provided, an array of results is
112
+ # returned. The behavior for each argument is that of a single argument,
113
+ # i.e. Strings, Symbols, and Regexps act like hash lookups, while
114
+ # Integers and Ranges act like Array index lookups.
115
+ #
116
+ # If no results are found, or an unhandled type is passed, then nil
117
+ # (or a nil element) is returned.
118
+ #
119
+ def [](*args)
120
+ begin
121
+ case args.length
122
+ when 0
123
+ err = "wrong # of arguments(#{args.size} for at least 1)"
124
+ raise ArgumentError, err
125
+ when 1
126
+ case args[0]
127
+ when Array
128
+ args[0].collect { |e| self[e] }
129
+ when Regexp
130
+ self[@column_names.grep(args[0])]
131
+ else
132
+ @arr[conv_param(args[0])]
133
+ end
134
+ # We explicitly check for a length of 2 in order to properly
135
+ # simulate the second form of Array#[].
136
+ when 2
137
+ @arr[conv_param(args[0]), conv_param(args[1])]
138
+ else
139
+ results = []
140
+ args.flatten.each{ |arg|
141
+ case arg
142
+ when Integer
143
+ results.push(@arr[arg])
144
+ when Regexp
145
+ results.push(self[@column_names.grep(arg)])
146
+ else
147
+ results.push(self[conv_param(arg)])
148
+ end
149
+ }
150
+ results.flatten
151
+ end
152
+ rescue TypeError
153
+ nil
154
+ end
155
+ end
156
+
157
+ # Assign a value to a Row object by element. You can assign using
158
+ # a single element reference, or by using a start and length similar
159
+ # to the second form of Array#[]=.
160
+ #
161
+ # row[0] = "kirk"
162
+ # row[:last] = "haines"
163
+ # row[0, 2] = "test"
164
+ #
165
+ def []=(key, value_or_length, obj=nil)
166
+ if obj
167
+ @arr[conv_param(key), conv_param(value_or_length)] = obj
168
+ else
169
+ @arr[conv_param(key)] = value_or_length
170
+ end
171
+ end
172
+
173
+ def clone
174
+ clone_with(@arr.dup)
175
+ end
176
+
177
+ alias dup clone
178
+
179
+ private
180
+
181
+ # Simple helper method to grab the proper value from @column_map
182
+ def conv_param(arg)
183
+ case arg
184
+ when String, Symbol
185
+ @column_map[arg.to_s]
186
+ when Range
187
+ if arg.first.kind_of?(Symbol) || arg.first.kind_of?(String)
188
+ first = @column_map[arg.first.to_s]
189
+ last = @column_map[arg.last.to_s]
190
+ else
191
+ first = arg.first
192
+ last = arg.last
193
+ end
194
+
195
+ if arg.exclude_end?
196
+ (first...last)
197
+ else
198
+ (first..last)
199
+ end
200
+ else
201
+ arg
202
+ end
203
+ end
204
+ end # class Row
205
+ end # module DBI
@@ -0,0 +1,239 @@
1
+ #
2
+ # $Id: sql.rb,v 1.3 2006/03/27 20:25:02 francis Exp $
3
+ #
4
+ # parts extracted from Jim Weirichs DBD::Pg
5
+ #
6
+
7
+ module DBI
8
+ require "dbi/utils"
9
+ require "parsedate"
10
+ require "time"
11
+
12
+ module SQL
13
+
14
+ ## Is the SQL statement a query?
15
+ def SQL.query?(sql)
16
+ sql =~ /^\s*select\b/i
17
+ end
18
+
19
+
20
+ ####################################################################
21
+ # Mixin module useful for expanding SQL statements.
22
+ #
23
+ module BasicQuote
24
+
25
+ # by Masatoshi SEKI
26
+ class Coerce
27
+ def as_int(str)
28
+ return nil if str.nil?
29
+ if str == "" then nil else str.to_i end
30
+ end
31
+
32
+ def as_float(str)
33
+ return nil if str.nil?
34
+ str.to_f
35
+ end
36
+
37
+ def as_str(str)
38
+ str
39
+ end
40
+
41
+ def as_bool(str)
42
+ if str == "t" or str == "1"
43
+ true
44
+ elsif str == "f" or str == "0"
45
+ false
46
+ else
47
+ nil
48
+ end
49
+ end
50
+
51
+ def as_time(str)
52
+ return nil if str.nil? or str.empty?
53
+ t = ParseDate.parsedate(str)
54
+ DBI::Time.new(*t[3,3])
55
+ end
56
+
57
+
58
+ def as_timestamp(str)
59
+ return nil if str.nil? or str.empty?
60
+ ary = ParseDate.parsedate(str)
61
+ begin
62
+ time = ::Time.gm(*(ary[0,6]))
63
+ rescue ArgumentError => ae
64
+ # don't fault stupid values that MySQL nevertheless stores
65
+ return nil
66
+ end
67
+ if ary[6] =~ /^((\+|\-)\d+)(:\d+)?$/
68
+ diff = $1.to_i * 3600 # seconds per hour
69
+ time -= diff
70
+ time.localtime
71
+ end
72
+ DBI::Timestamp.new(time)
73
+ end
74
+
75
+
76
+ def as_date(str)
77
+ return nil if str.nil?
78
+ ary = ParseDate.parsedate(str)
79
+ DBI::Date.new(*ary[0,3])
80
+ rescue
81
+ nil
82
+ end
83
+
84
+
85
+ def coerce(sym, str)
86
+ self.send(sym, str)
87
+ end
88
+
89
+ end # class Coerce
90
+
91
+
92
+ ## Quote strings appropriately for SQL statements
93
+ def quote(value)
94
+ case value
95
+ when String
96
+ value = value.gsub(/'/, "''") # ' (for ruby-mode)
97
+ "'#{value}'"
98
+ when NilClass
99
+ "NULL"
100
+ when TrueClass
101
+ "'t'"
102
+ when FalseClass
103
+ "'f'"
104
+ when Array
105
+ value.collect { |v| quote(v) }.join(", ")
106
+ when DBI::Date, DBI::Time, DBI::Timestamp, ::Date
107
+ "'#{value.to_s}'"
108
+ when ::Time
109
+ "'#{value.rfc2822}'"
110
+ else
111
+ value.to_s
112
+ end
113
+ end
114
+ end # module BasicQuote
115
+
116
+
117
+
118
+ ####################################################################
119
+ # Mixin module useful for binding arguments to an SQL string.
120
+ #
121
+ module BasicBind
122
+
123
+ ## Bind the :sql string to an array of :args, quoting with :quoter.
124
+ #
125
+ def bind(quoter, sql, args)
126
+ arg_index = 0
127
+ result = ""
128
+ tokens(sql).each { |part|
129
+ case part
130
+ when '?'
131
+ result << quoter.quote(args[arg_index])
132
+ arg_index += 1
133
+ when '??'
134
+ result << "?"
135
+ else
136
+ result << part
137
+ end
138
+ }
139
+ if arg_index < args.size
140
+ raise "Too many SQL parameters"
141
+ elsif arg_index > args.size
142
+ raise "Not enough SQL parameters"
143
+ end
144
+ result
145
+ end
146
+
147
+ ## Break the sql string into parts.
148
+ #
149
+ # This is NOT a full lexer for SQL. It just breaks up the SQL
150
+ # string enough so that question marks, double question marks and
151
+ # quoted strings are separated. This is used when binding
152
+ # arguments to "?" in the SQL string.
153
+ #
154
+ # C-style (/* */) and Ada-style (--) comments are handled.
155
+ # Note: Nested C-style comments are NOT handled!
156
+ #
157
+ def tokens(sql)
158
+ sql.scan(%r{
159
+ (
160
+ -- .* (?# matches "--" style comments to the end of line or string )
161
+ | - (?# matches single "-" )
162
+ |
163
+ /[*] .*? [*]/ (?# matches C-style comments )
164
+ | / (?# matches single slash )
165
+ |
166
+ ' ( [^'\\] | '' | \\. )* ' (?# match strings surrounded by apostophes )
167
+ |
168
+ " ( [^"\\] | "" | \\. )* " (?# match strings surrounded by " )
169
+ |
170
+ \?\?? (?# match one or two question marks )
171
+ |
172
+ [^-/'"?]+ (?# match all characters except ' " ? - and / )
173
+
174
+ )}x).collect {|t| t.first}
175
+ end
176
+
177
+ end # module BasicBind
178
+
179
+
180
+ class PreparedStatement
181
+ include BasicBind # for method tokens(sql)
182
+
183
+ attr_accessor :unbound
184
+
185
+ def initialize(quoter, sql)
186
+ @quoter, @sql = quoter, sql
187
+ prepare
188
+ end
189
+
190
+ def bind(args)
191
+ if @arg_index < args.size
192
+ raise "Too many SQL parameters"
193
+ elsif @arg_index > args.size
194
+ raise "Not enough SQL parameters"
195
+ end
196
+
197
+ @unbound.each do |res_pos, arg_pos|
198
+ @result[res_pos] = @quoter.quote(args[arg_pos])
199
+ end
200
+
201
+ @result.join("")
202
+ end
203
+
204
+ private
205
+
206
+ def prepare
207
+ @result = []
208
+ @unbound = {}
209
+ pos = 0
210
+ @arg_index = 0
211
+
212
+ tokens(@sql).each { |part|
213
+ case part
214
+ when '?'
215
+ @result[pos] = nil
216
+ @unbound[pos] = @arg_index
217
+ pos += 1
218
+ @arg_index += 1
219
+ when '??'
220
+ if @result[pos-1] != nil
221
+ @result[pos-1] << "?"
222
+ else
223
+ @result[pos] = "?"
224
+ pos += 1
225
+ end
226
+ else
227
+ if @result[pos-1] != nil
228
+ @result[pos-1] << part
229
+ else
230
+ @result[pos] = part
231
+ pos += 1
232
+ end
233
+ end
234
+ }
235
+ end
236
+ end
237
+
238
+ end # module SQL
239
+ end # module DBI