akitaonrails-activerecord-sqlserver-adapter 1.1.0 → 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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