activerecord 4.1.0 → 4.2.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +776 -1330
- data/README.rdoc +15 -10
- data/lib/active_record/aggregations.rb +12 -8
- data/lib/active_record/association_relation.rb +4 -0
- data/lib/active_record/associations/alias_tracker.rb +14 -13
- data/lib/active_record/associations/association.rb +2 -2
- data/lib/active_record/associations/association_scope.rb +83 -43
- data/lib/active_record/associations/belongs_to_association.rb +15 -5
- data/lib/active_record/associations/builder/association.rb +15 -4
- data/lib/active_record/associations/builder/belongs_to.rb +7 -29
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +9 -6
- data/lib/active_record/associations/builder/has_many.rb +1 -1
- data/lib/active_record/associations/builder/has_one.rb +2 -2
- data/lib/active_record/associations/builder/singular_association.rb +8 -1
- data/lib/active_record/associations/collection_association.rb +66 -29
- data/lib/active_record/associations/collection_proxy.rb +22 -26
- data/lib/active_record/associations/has_many_association.rb +65 -18
- data/lib/active_record/associations/has_many_through_association.rb +55 -27
- data/lib/active_record/associations/has_one_association.rb +0 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +19 -15
- data/lib/active_record/associations/join_dependency/join_part.rb +0 -1
- data/lib/active_record/associations/join_dependency.rb +20 -12
- data/lib/active_record/associations/preloader/association.rb +34 -11
- data/lib/active_record/associations/preloader/through_association.rb +4 -3
- data/lib/active_record/associations/preloader.rb +49 -59
- data/lib/active_record/associations/singular_association.rb +25 -4
- data/lib/active_record/associations/through_association.rb +23 -14
- data/lib/active_record/associations.rb +171 -42
- data/lib/active_record/attribute.rb +149 -0
- data/lib/active_record/attribute_assignment.rb +18 -10
- data/lib/active_record/attribute_decorators.rb +66 -0
- data/lib/active_record/attribute_methods/before_type_cast.rb +2 -2
- data/lib/active_record/attribute_methods/dirty.rb +98 -44
- data/lib/active_record/attribute_methods/primary_key.rb +14 -8
- data/lib/active_record/attribute_methods/query.rb +1 -1
- data/lib/active_record/attribute_methods/read.rb +22 -59
- data/lib/active_record/attribute_methods/serialization.rb +37 -147
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +34 -28
- data/lib/active_record/attribute_methods/write.rb +14 -21
- data/lib/active_record/attribute_methods.rb +67 -94
- data/lib/active_record/attribute_set/builder.rb +86 -0
- data/lib/active_record/attribute_set.rb +77 -0
- data/lib/active_record/attributes.rb +139 -0
- data/lib/active_record/autosave_association.rb +45 -38
- data/lib/active_record/base.rb +10 -20
- data/lib/active_record/callbacks.rb +7 -7
- data/lib/active_record/coders/json.rb +13 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +78 -52
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +38 -59
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +1 -0
- data/lib/active_record/connection_adapters/abstract/quoting.rb +59 -55
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +46 -5
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +126 -54
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -34
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +198 -64
- data/lib/active_record/connection_adapters/abstract/transaction.rb +126 -114
- data/lib/active_record/connection_adapters/abstract_adapter.rb +154 -55
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +240 -135
- data/lib/active_record/connection_adapters/column.rb +28 -239
- data/lib/active_record/connection_adapters/connection_specification.rb +16 -25
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +20 -22
- data/lib/active_record/connection_adapters/mysql_adapter.rb +65 -149
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +15 -27
- data/lib/active_record/connection_adapters/postgresql/column.rb +20 -0
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +39 -27
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +99 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +52 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +14 -0
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +46 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +11 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +27 -0
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +17 -0
- data/lib/active_record/connection_adapters/postgresql/oid/float.rb +21 -0
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +59 -0
- data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +11 -0
- data/lib/active_record/connection_adapters/postgresql/oid/json.rb +35 -0
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +23 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +79 -0
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/time.rb +11 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +97 -0
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +21 -0
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +26 -0
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +28 -0
- data/lib/active_record/connection_adapters/postgresql/oid.rb +29 -374
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +55 -135
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +4 -4
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +152 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +127 -38
- data/lib/active_record/connection_adapters/postgresql/utils.rb +77 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +220 -466
- data/lib/active_record/connection_adapters/schema_cache.rb +14 -28
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +66 -61
- data/lib/active_record/connection_handling.rb +3 -3
- data/lib/active_record/core.rb +143 -32
- data/lib/active_record/counter_cache.rb +60 -7
- data/lib/active_record/enum.rb +10 -11
- data/lib/active_record/errors.rb +49 -27
- data/lib/active_record/explain.rb +1 -1
- data/lib/active_record/fixtures.rb +56 -70
- data/lib/active_record/gem_version.rb +2 -2
- data/lib/active_record/inheritance.rb +35 -10
- data/lib/active_record/integration.rb +4 -4
- data/lib/active_record/locking/optimistic.rb +35 -17
- data/lib/active_record/log_subscriber.rb +1 -1
- data/lib/active_record/migration/command_recorder.rb +19 -2
- data/lib/active_record/migration/join_table.rb +1 -1
- data/lib/active_record/migration.rb +52 -49
- data/lib/active_record/model_schema.rb +49 -57
- data/lib/active_record/nested_attributes.rb +7 -7
- data/lib/active_record/null_relation.rb +19 -5
- data/lib/active_record/persistence.rb +50 -31
- data/lib/active_record/query_cache.rb +3 -3
- data/lib/active_record/querying.rb +10 -7
- data/lib/active_record/railtie.rb +14 -11
- data/lib/active_record/railties/databases.rake +56 -54
- data/lib/active_record/readonly_attributes.rb +0 -1
- data/lib/active_record/reflection.rb +286 -102
- data/lib/active_record/relation/batches.rb +0 -1
- data/lib/active_record/relation/calculations.rb +39 -31
- data/lib/active_record/relation/delegation.rb +2 -2
- data/lib/active_record/relation/finder_methods.rb +80 -36
- data/lib/active_record/relation/merger.rb +25 -30
- data/lib/active_record/relation/predicate_builder/array_handler.rb +31 -13
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
- data/lib/active_record/relation/predicate_builder.rb +11 -10
- data/lib/active_record/relation/query_methods.rb +141 -55
- data/lib/active_record/relation/spawn_methods.rb +3 -0
- data/lib/active_record/relation.rb +69 -30
- data/lib/active_record/result.rb +18 -7
- data/lib/active_record/sanitization.rb +12 -2
- data/lib/active_record/schema.rb +0 -1
- data/lib/active_record/schema_dumper.rb +58 -26
- data/lib/active_record/schema_migration.rb +11 -0
- data/lib/active_record/scoping/default.rb +8 -7
- data/lib/active_record/scoping/named.rb +4 -0
- data/lib/active_record/serializers/xml_serializer.rb +3 -7
- data/lib/active_record/statement_cache.rb +95 -10
- data/lib/active_record/store.rb +19 -10
- data/lib/active_record/tasks/database_tasks.rb +73 -7
- data/lib/active_record/tasks/mysql_database_tasks.rb +3 -2
- data/lib/active_record/tasks/postgresql_database_tasks.rb +1 -1
- data/lib/active_record/tasks/sqlite_database_tasks.rb +5 -1
- data/lib/active_record/timestamp.rb +11 -9
- data/lib/active_record/transactions.rb +37 -21
- data/lib/active_record/type/big_integer.rb +13 -0
- data/lib/active_record/type/binary.rb +50 -0
- data/lib/active_record/type/boolean.rb +30 -0
- data/lib/active_record/type/date.rb +46 -0
- data/lib/active_record/type/date_time.rb +43 -0
- data/lib/active_record/type/decimal.rb +40 -0
- data/lib/active_record/type/decimal_without_scale.rb +11 -0
- data/lib/active_record/type/decorator.rb +14 -0
- data/lib/active_record/type/float.rb +19 -0
- data/lib/active_record/type/hash_lookup_type_map.rb +17 -0
- data/lib/active_record/type/integer.rb +55 -0
- data/lib/active_record/type/mutable.rb +16 -0
- data/lib/active_record/type/numeric.rb +36 -0
- data/lib/active_record/type/serialized.rb +56 -0
- data/lib/active_record/type/string.rb +36 -0
- data/lib/active_record/type/text.rb +11 -0
- data/lib/active_record/type/time.rb +26 -0
- data/lib/active_record/type/time_value.rb +38 -0
- data/lib/active_record/type/type_map.rb +64 -0
- data/lib/active_record/type/unsigned_integer.rb +15 -0
- data/lib/active_record/type/value.rb +101 -0
- data/lib/active_record/type.rb +23 -0
- data/lib/active_record/validations/associated.rb +5 -3
- data/lib/active_record/validations/presence.rb +6 -4
- data/lib/active_record/validations/uniqueness.rb +11 -17
- data/lib/active_record/validations.rb +25 -19
- data/lib/active_record.rb +3 -0
- data/lib/rails/generators/active_record/migration/migration_generator.rb +8 -4
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +4 -1
- data/lib/rails/generators/active_record/migration/templates/migration.rb +6 -0
- data/lib/rails/generators/active_record/model/templates/model.rb +1 -1
- metadata +65 -10
- data/lib/active_record/connection_adapters/postgresql/cast.rb +0 -168
@@ -0,0 +1,28 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module ConnectionAdapters
|
3
|
+
module PostgreSQL
|
4
|
+
module OID # :nodoc:
|
5
|
+
class Xml < Type::String # :nodoc:
|
6
|
+
def type
|
7
|
+
:xml
|
8
|
+
end
|
9
|
+
|
10
|
+
def type_cast_for_database(value)
|
11
|
+
return unless value
|
12
|
+
Data.new(super)
|
13
|
+
end
|
14
|
+
|
15
|
+
class Data # :nodoc:
|
16
|
+
def initialize(value)
|
17
|
+
@value = value
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_s
|
21
|
+
@value
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -1,380 +1,35 @@
|
|
1
|
-
require 'active_record/connection_adapters/
|
1
|
+
require 'active_record/connection_adapters/postgresql/oid/infinity'
|
2
|
+
|
3
|
+
require 'active_record/connection_adapters/postgresql/oid/array'
|
4
|
+
require 'active_record/connection_adapters/postgresql/oid/bit'
|
5
|
+
require 'active_record/connection_adapters/postgresql/oid/bit_varying'
|
6
|
+
require 'active_record/connection_adapters/postgresql/oid/bytea'
|
7
|
+
require 'active_record/connection_adapters/postgresql/oid/cidr'
|
8
|
+
require 'active_record/connection_adapters/postgresql/oid/date'
|
9
|
+
require 'active_record/connection_adapters/postgresql/oid/date_time'
|
10
|
+
require 'active_record/connection_adapters/postgresql/oid/decimal'
|
11
|
+
require 'active_record/connection_adapters/postgresql/oid/enum'
|
12
|
+
require 'active_record/connection_adapters/postgresql/oid/float'
|
13
|
+
require 'active_record/connection_adapters/postgresql/oid/hstore'
|
14
|
+
require 'active_record/connection_adapters/postgresql/oid/inet'
|
15
|
+
require 'active_record/connection_adapters/postgresql/oid/integer'
|
16
|
+
require 'active_record/connection_adapters/postgresql/oid/json'
|
17
|
+
require 'active_record/connection_adapters/postgresql/oid/jsonb'
|
18
|
+
require 'active_record/connection_adapters/postgresql/oid/money'
|
19
|
+
require 'active_record/connection_adapters/postgresql/oid/point'
|
20
|
+
require 'active_record/connection_adapters/postgresql/oid/range'
|
21
|
+
require 'active_record/connection_adapters/postgresql/oid/specialized_string'
|
22
|
+
require 'active_record/connection_adapters/postgresql/oid/time'
|
23
|
+
require 'active_record/connection_adapters/postgresql/oid/uuid'
|
24
|
+
require 'active_record/connection_adapters/postgresql/oid/vector'
|
25
|
+
require 'active_record/connection_adapters/postgresql/oid/xml'
|
26
|
+
|
27
|
+
require 'active_record/connection_adapters/postgresql/oid/type_map_initializer'
|
2
28
|
|
3
29
|
module ActiveRecord
|
4
30
|
module ConnectionAdapters
|
5
|
-
|
6
|
-
module OID
|
7
|
-
class Type
|
8
|
-
def type; end
|
9
|
-
end
|
10
|
-
|
11
|
-
class Identity < Type
|
12
|
-
def type_cast(value)
|
13
|
-
value
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
class Bit < Type
|
18
|
-
def type_cast(value)
|
19
|
-
if String === value
|
20
|
-
ConnectionAdapters::PostgreSQLColumn.string_to_bit value
|
21
|
-
else
|
22
|
-
value
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
class Bytea < Type
|
28
|
-
def type_cast(value)
|
29
|
-
return if value.nil?
|
30
|
-
PGconn.unescape_bytea value
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
class Money < Type
|
35
|
-
def type_cast(value)
|
36
|
-
return if value.nil?
|
37
|
-
return value unless String === value
|
38
|
-
|
39
|
-
# Because money output is formatted according to the locale, there are two
|
40
|
-
# cases to consider (note the decimal separators):
|
41
|
-
# (1) $12,345,678.12
|
42
|
-
# (2) $12.345.678,12
|
43
|
-
# Negative values are represented as follows:
|
44
|
-
# (3) -$2.55
|
45
|
-
# (4) ($2.55)
|
46
|
-
|
47
|
-
value.sub!(/^\((.+)\)$/, '-\1') # (4)
|
48
|
-
case value
|
49
|
-
when /^-?\D+[\d,]+\.\d{2}$/ # (1)
|
50
|
-
value.gsub!(/[^-\d.]/, '')
|
51
|
-
when /^-?\D+[\d.]+,\d{2}$/ # (2)
|
52
|
-
value.gsub!(/[^-\d,]/, '').sub!(/,/, '.')
|
53
|
-
end
|
54
|
-
|
55
|
-
ConnectionAdapters::Column.value_to_decimal value
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
class Vector < Type
|
60
|
-
attr_reader :delim, :subtype
|
61
|
-
|
62
|
-
# +delim+ corresponds to the `typdelim` column in the pg_types
|
63
|
-
# table. +subtype+ is derived from the `typelem` column in the
|
64
|
-
# pg_types table.
|
65
|
-
def initialize(delim, subtype)
|
66
|
-
@delim = delim
|
67
|
-
@subtype = subtype
|
68
|
-
end
|
69
|
-
|
70
|
-
# FIXME: this should probably split on +delim+ and use +subtype+
|
71
|
-
# to cast the values. Unfortunately, the current Rails behavior
|
72
|
-
# is to just return the string.
|
73
|
-
def type_cast(value)
|
74
|
-
value
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
class Point < Type
|
79
|
-
def type_cast(value)
|
80
|
-
if String === value
|
81
|
-
ConnectionAdapters::PostgreSQLColumn.string_to_point value
|
82
|
-
else
|
83
|
-
value
|
84
|
-
end
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
class Array < Type
|
89
|
-
attr_reader :subtype
|
90
|
-
def initialize(subtype)
|
91
|
-
@subtype = subtype
|
92
|
-
end
|
93
|
-
|
94
|
-
def type_cast(value)
|
95
|
-
if String === value
|
96
|
-
ConnectionAdapters::PostgreSQLColumn.string_to_array value, @subtype
|
97
|
-
else
|
98
|
-
value
|
99
|
-
end
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
class Range < Type
|
104
|
-
attr_reader :subtype
|
105
|
-
def initialize(subtype)
|
106
|
-
@subtype = subtype
|
107
|
-
end
|
108
|
-
|
109
|
-
def extract_bounds(value)
|
110
|
-
from, to = value[1..-2].split(',')
|
111
|
-
{
|
112
|
-
from: (value[1] == ',' || from == '-infinity') ? infinity(:negative => true) : from,
|
113
|
-
to: (value[-2] == ',' || to == 'infinity') ? infinity : to,
|
114
|
-
exclude_start: (value[0] == '('),
|
115
|
-
exclude_end: (value[-1] == ')')
|
116
|
-
}
|
117
|
-
end
|
118
|
-
|
119
|
-
def infinity(options = {})
|
120
|
-
::Float::INFINITY * (options[:negative] ? -1 : 1)
|
121
|
-
end
|
122
|
-
|
123
|
-
def infinity?(value)
|
124
|
-
value.respond_to?(:infinite?) && value.infinite?
|
125
|
-
end
|
126
|
-
|
127
|
-
def to_integer(value)
|
128
|
-
infinity?(value) ? value : value.to_i
|
129
|
-
end
|
130
|
-
|
131
|
-
def type_cast(value)
|
132
|
-
return if value.nil? || value == 'empty'
|
133
|
-
return value if value.is_a?(::Range)
|
134
|
-
|
135
|
-
extracted = extract_bounds(value)
|
136
|
-
|
137
|
-
case @subtype
|
138
|
-
when :date
|
139
|
-
from = ConnectionAdapters::Column.value_to_date(extracted[:from])
|
140
|
-
from -= 1.day if extracted[:exclude_start]
|
141
|
-
to = ConnectionAdapters::Column.value_to_date(extracted[:to])
|
142
|
-
when :decimal
|
143
|
-
from = BigDecimal.new(extracted[:from].to_s)
|
144
|
-
# FIXME: add exclude start for ::Range, same for timestamp ranges
|
145
|
-
to = BigDecimal.new(extracted[:to].to_s)
|
146
|
-
when :time
|
147
|
-
from = ConnectionAdapters::Column.string_to_time(extracted[:from])
|
148
|
-
to = ConnectionAdapters::Column.string_to_time(extracted[:to])
|
149
|
-
when :integer
|
150
|
-
from = to_integer(extracted[:from]) rescue value ? 1 : 0
|
151
|
-
from -= 1 if extracted[:exclude_start]
|
152
|
-
to = to_integer(extracted[:to]) rescue value ? 1 : 0
|
153
|
-
else
|
154
|
-
return value
|
155
|
-
end
|
156
|
-
|
157
|
-
::Range.new(from, to, extracted[:exclude_end])
|
158
|
-
end
|
159
|
-
end
|
160
|
-
|
161
|
-
class Integer < Type
|
162
|
-
def type_cast(value)
|
163
|
-
return if value.nil?
|
164
|
-
|
165
|
-
ConnectionAdapters::Column.value_to_integer value
|
166
|
-
end
|
167
|
-
end
|
168
|
-
|
169
|
-
class Boolean < Type
|
170
|
-
def type_cast(value)
|
171
|
-
return if value.nil?
|
172
|
-
|
173
|
-
ConnectionAdapters::Column.value_to_boolean value
|
174
|
-
end
|
175
|
-
end
|
176
|
-
|
177
|
-
class Timestamp < Type
|
178
|
-
def type; :timestamp; end
|
179
|
-
|
180
|
-
def type_cast(value)
|
181
|
-
return if value.nil?
|
182
|
-
|
183
|
-
# FIXME: probably we can improve this since we know it is PG
|
184
|
-
# specific
|
185
|
-
ConnectionAdapters::PostgreSQLColumn.string_to_time value
|
186
|
-
end
|
187
|
-
end
|
188
|
-
|
189
|
-
class Date < Type
|
190
|
-
def type; :datetime; end
|
191
|
-
|
192
|
-
def type_cast(value)
|
193
|
-
return if value.nil?
|
194
|
-
|
195
|
-
# FIXME: probably we can improve this since we know it is PG
|
196
|
-
# specific
|
197
|
-
ConnectionAdapters::Column.value_to_date value
|
198
|
-
end
|
199
|
-
end
|
200
|
-
|
201
|
-
class Time < Type
|
202
|
-
def type_cast(value)
|
203
|
-
return if value.nil?
|
204
|
-
|
205
|
-
# FIXME: probably we can improve this since we know it is PG
|
206
|
-
# specific
|
207
|
-
ConnectionAdapters::Column.string_to_dummy_time value
|
208
|
-
end
|
209
|
-
end
|
210
|
-
|
211
|
-
class Float < Type
|
212
|
-
def type_cast(value)
|
213
|
-
return if value.nil?
|
214
|
-
|
215
|
-
value.to_f
|
216
|
-
end
|
217
|
-
end
|
218
|
-
|
219
|
-
class Decimal < Type
|
220
|
-
def type_cast(value)
|
221
|
-
return if value.nil?
|
222
|
-
|
223
|
-
ConnectionAdapters::Column.value_to_decimal value
|
224
|
-
end
|
225
|
-
end
|
226
|
-
|
227
|
-
class Hstore < Type
|
228
|
-
def type_cast_for_write(value)
|
229
|
-
ConnectionAdapters::PostgreSQLColumn.hstore_to_string value
|
230
|
-
end
|
231
|
-
|
232
|
-
def type_cast(value)
|
233
|
-
return if value.nil?
|
234
|
-
|
235
|
-
ConnectionAdapters::PostgreSQLColumn.string_to_hstore value
|
236
|
-
end
|
237
|
-
|
238
|
-
def accessor
|
239
|
-
ActiveRecord::Store::StringKeyedHashAccessor
|
240
|
-
end
|
241
|
-
end
|
242
|
-
|
243
|
-
class Cidr < Type
|
244
|
-
def type_cast(value)
|
245
|
-
return if value.nil?
|
246
|
-
|
247
|
-
ConnectionAdapters::PostgreSQLColumn.string_to_cidr value
|
248
|
-
end
|
249
|
-
end
|
250
|
-
|
251
|
-
class Json < Type
|
252
|
-
def type_cast_for_write(value)
|
253
|
-
ConnectionAdapters::PostgreSQLColumn.json_to_string value
|
254
|
-
end
|
255
|
-
|
256
|
-
def type_cast(value)
|
257
|
-
return if value.nil?
|
258
|
-
|
259
|
-
ConnectionAdapters::PostgreSQLColumn.string_to_json value
|
260
|
-
end
|
261
|
-
|
262
|
-
def accessor
|
263
|
-
ActiveRecord::Store::StringKeyedHashAccessor
|
264
|
-
end
|
265
|
-
end
|
266
|
-
|
267
|
-
class TypeMap
|
268
|
-
def initialize
|
269
|
-
@mapping = {}
|
270
|
-
end
|
271
|
-
|
272
|
-
def []=(oid, type)
|
273
|
-
@mapping[oid] = type
|
274
|
-
end
|
275
|
-
|
276
|
-
def [](oid)
|
277
|
-
@mapping[oid]
|
278
|
-
end
|
279
|
-
|
280
|
-
def clear
|
281
|
-
@mapping.clear
|
282
|
-
end
|
283
|
-
|
284
|
-
def key?(oid)
|
285
|
-
@mapping.key? oid
|
286
|
-
end
|
287
|
-
|
288
|
-
def fetch(ftype, fmod)
|
289
|
-
# The type for the numeric depends on the width of the field,
|
290
|
-
# so we'll do something special here.
|
291
|
-
#
|
292
|
-
# When dealing with decimal columns:
|
293
|
-
#
|
294
|
-
# places after decimal = fmod - 4 & 0xffff
|
295
|
-
# places before decimal = (fmod - 4) >> 16 & 0xffff
|
296
|
-
if ftype == 1700 && (fmod - 4 & 0xffff).zero?
|
297
|
-
ftype = 23
|
298
|
-
end
|
299
|
-
|
300
|
-
@mapping.fetch(ftype) { |oid| yield oid, fmod }
|
301
|
-
end
|
302
|
-
end
|
303
|
-
|
304
|
-
# When the PG adapter connects, the pg_type table is queried. The
|
305
|
-
# key of this hash maps to the `typname` column from the table.
|
306
|
-
# type_map is then dynamically built with oids as the key and type
|
307
|
-
# objects as values.
|
308
|
-
NAMES = Hash.new { |h,k| # :nodoc:
|
309
|
-
h[k] = OID::Identity.new
|
310
|
-
}
|
311
|
-
|
312
|
-
# Register an OID type named +name+ with a typecasting object in
|
313
|
-
# +type+. +name+ should correspond to the `typname` column in
|
314
|
-
# the `pg_type` table.
|
315
|
-
def self.register_type(name, type)
|
316
|
-
NAMES[name] = type
|
317
|
-
end
|
318
|
-
|
319
|
-
# Alias the +old+ type to the +new+ type.
|
320
|
-
def self.alias_type(new, old)
|
321
|
-
NAMES[new] = NAMES[old]
|
322
|
-
end
|
323
|
-
|
324
|
-
# Is +name+ a registered type?
|
325
|
-
def self.registered_type?(name)
|
326
|
-
NAMES.key? name
|
327
|
-
end
|
328
|
-
|
329
|
-
register_type 'int2', OID::Integer.new
|
330
|
-
alias_type 'int4', 'int2'
|
331
|
-
alias_type 'int8', 'int2'
|
332
|
-
alias_type 'oid', 'int2'
|
333
|
-
|
334
|
-
register_type 'daterange', OID::Range.new(:date)
|
335
|
-
register_type 'numrange', OID::Range.new(:decimal)
|
336
|
-
register_type 'tsrange', OID::Range.new(:time)
|
337
|
-
register_type 'int4range', OID::Range.new(:integer)
|
338
|
-
alias_type 'tstzrange', 'tsrange'
|
339
|
-
alias_type 'int8range', 'int4range'
|
340
|
-
|
341
|
-
register_type 'numeric', OID::Decimal.new
|
342
|
-
register_type 'text', OID::Identity.new
|
343
|
-
alias_type 'varchar', 'text'
|
344
|
-
alias_type 'char', 'text'
|
345
|
-
alias_type 'bpchar', 'text'
|
346
|
-
alias_type 'xml', 'text'
|
347
|
-
|
348
|
-
# FIXME: why are we keeping these types as strings?
|
349
|
-
alias_type 'tsvector', 'text'
|
350
|
-
alias_type 'interval', 'text'
|
351
|
-
alias_type 'macaddr', 'text'
|
352
|
-
alias_type 'uuid', 'text'
|
353
|
-
|
354
|
-
register_type 'money', OID::Money.new
|
355
|
-
register_type 'bytea', OID::Bytea.new
|
356
|
-
register_type 'bool', OID::Boolean.new
|
357
|
-
register_type 'bit', OID::Bit.new
|
358
|
-
register_type 'varbit', OID::Bit.new
|
359
|
-
|
360
|
-
register_type 'float4', OID::Float.new
|
361
|
-
alias_type 'float8', 'float4'
|
362
|
-
|
363
|
-
register_type 'timestamp', OID::Timestamp.new
|
364
|
-
register_type 'timestamptz', OID::Timestamp.new
|
365
|
-
register_type 'date', OID::Date.new
|
366
|
-
register_type 'time', OID::Time.new
|
367
|
-
|
368
|
-
register_type 'path', OID::Identity.new
|
369
|
-
register_type 'point', OID::Point.new
|
370
|
-
register_type 'polygon', OID::Identity.new
|
371
|
-
register_type 'circle', OID::Identity.new
|
372
|
-
register_type 'hstore', OID::Hstore.new
|
373
|
-
register_type 'json', OID::Json.new
|
374
|
-
register_type 'ltree', OID::Identity.new
|
375
|
-
|
376
|
-
register_type 'cidr', OID::Cidr.new
|
377
|
-
alias_type 'inet', 'cidr'
|
31
|
+
module PostgreSQL
|
32
|
+
module OID # :nodoc:
|
378
33
|
end
|
379
34
|
end
|
380
35
|
end
|
@@ -1,139 +1,17 @@
|
|
1
1
|
module ActiveRecord
|
2
2
|
module ConnectionAdapters
|
3
|
-
|
3
|
+
module PostgreSQL
|
4
4
|
module Quoting
|
5
5
|
# Escapes binary strings for bytea input to the database.
|
6
6
|
def escape_bytea(value)
|
7
|
-
|
7
|
+
@connection.escape_bytea(value) if value
|
8
8
|
end
|
9
9
|
|
10
10
|
# Unescapes bytea output from a database to the binary string it represents.
|
11
11
|
# NOTE: This is NOT an inverse of escape_bytea! This is only to be used
|
12
12
|
# on escaped binary output from database drive.
|
13
13
|
def unescape_bytea(value)
|
14
|
-
|
15
|
-
end
|
16
|
-
|
17
|
-
# Quotes PostgreSQL-specific data types for SQL input.
|
18
|
-
def quote(value, column = nil) #:nodoc:
|
19
|
-
return super unless column
|
20
|
-
|
21
|
-
sql_type = type_to_sql(column.type, column.limit, column.precision, column.scale)
|
22
|
-
|
23
|
-
case value
|
24
|
-
when Range
|
25
|
-
if /range$/ =~ sql_type
|
26
|
-
"'#{PostgreSQLColumn.range_to_string(value)}'::#{sql_type}"
|
27
|
-
else
|
28
|
-
super
|
29
|
-
end
|
30
|
-
when Array
|
31
|
-
case sql_type
|
32
|
-
when 'point' then super(PostgreSQLColumn.point_to_string(value))
|
33
|
-
when 'json' then super(PostgreSQLColumn.json_to_string(value))
|
34
|
-
else
|
35
|
-
if column.array
|
36
|
-
"'#{PostgreSQLColumn.array_to_string(value, column, self).gsub(/'/, "''")}'"
|
37
|
-
else
|
38
|
-
super
|
39
|
-
end
|
40
|
-
end
|
41
|
-
when Hash
|
42
|
-
case sql_type
|
43
|
-
when 'hstore' then super(PostgreSQLColumn.hstore_to_string(value), column)
|
44
|
-
when 'json' then super(PostgreSQLColumn.json_to_string(value), column)
|
45
|
-
else super
|
46
|
-
end
|
47
|
-
when IPAddr
|
48
|
-
case sql_type
|
49
|
-
when 'inet', 'cidr' then super(PostgreSQLColumn.cidr_to_string(value), column)
|
50
|
-
else super
|
51
|
-
end
|
52
|
-
when Float
|
53
|
-
if value.infinite? && column.type == :datetime
|
54
|
-
"'#{value.to_s.downcase}'"
|
55
|
-
elsif value.infinite? || value.nan?
|
56
|
-
"'#{value.to_s}'"
|
57
|
-
else
|
58
|
-
super
|
59
|
-
end
|
60
|
-
when Numeric
|
61
|
-
if sql_type == 'money' || [:string, :text].include?(column.type)
|
62
|
-
# Not truly string input, so doesn't require (or allow) escape string syntax.
|
63
|
-
"'#{value}'"
|
64
|
-
else
|
65
|
-
super
|
66
|
-
end
|
67
|
-
when String
|
68
|
-
case sql_type
|
69
|
-
when 'bytea' then "'#{escape_bytea(value)}'"
|
70
|
-
when 'xml' then "xml '#{quote_string(value)}'"
|
71
|
-
when /^bit/
|
72
|
-
case value
|
73
|
-
when /^[01]*$/ then "B'#{value}'" # Bit-string notation
|
74
|
-
when /^[0-9A-F]*$/i then "X'#{value}'" # Hexadecimal notation
|
75
|
-
end
|
76
|
-
else
|
77
|
-
super
|
78
|
-
end
|
79
|
-
else
|
80
|
-
super
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
def type_cast(value, column, array_member = false)
|
85
|
-
return super(value, column) unless column
|
86
|
-
|
87
|
-
case value
|
88
|
-
when Range
|
89
|
-
if /range$/ =~ column.sql_type
|
90
|
-
PostgreSQLColumn.range_to_string(value)
|
91
|
-
else
|
92
|
-
super(value, column)
|
93
|
-
end
|
94
|
-
when NilClass
|
95
|
-
if column.array && array_member
|
96
|
-
'NULL'
|
97
|
-
elsif column.array
|
98
|
-
value
|
99
|
-
else
|
100
|
-
super(value, column)
|
101
|
-
end
|
102
|
-
when Array
|
103
|
-
case column.sql_type
|
104
|
-
when 'point' then PostgreSQLColumn.point_to_string(value)
|
105
|
-
when 'json' then PostgreSQLColumn.json_to_string(value)
|
106
|
-
else
|
107
|
-
if column.array
|
108
|
-
PostgreSQLColumn.array_to_string(value, column, self)
|
109
|
-
else
|
110
|
-
super(value, column)
|
111
|
-
end
|
112
|
-
end
|
113
|
-
when String
|
114
|
-
if 'bytea' == column.sql_type
|
115
|
-
# Return a bind param hash with format as binary.
|
116
|
-
# See http://deveiate.org/code/pg/PGconn.html#method-i-exec_prepared-doc
|
117
|
-
# for more information
|
118
|
-
{ value: value, format: 1 }
|
119
|
-
else
|
120
|
-
super(value, column)
|
121
|
-
end
|
122
|
-
when Hash
|
123
|
-
case column.sql_type
|
124
|
-
when 'hstore' then PostgreSQLColumn.hstore_to_string(value, array_member)
|
125
|
-
when 'json' then PostgreSQLColumn.json_to_string(value)
|
126
|
-
else super(value, column)
|
127
|
-
end
|
128
|
-
when IPAddr
|
129
|
-
if %w(inet cidr).include? column.sql_type
|
130
|
-
PostgreSQLColumn.cidr_to_string(value)
|
131
|
-
else
|
132
|
-
super(value, column)
|
133
|
-
end
|
134
|
-
else
|
135
|
-
super(value, column)
|
136
|
-
end
|
14
|
+
@connection.unescape_bytea(value) if value
|
137
15
|
end
|
138
16
|
|
139
17
|
# Quotes strings for use in SQL input.
|
@@ -150,14 +28,7 @@ module ActiveRecord
|
|
150
28
|
# - "schema.name".table_name
|
151
29
|
# - "schema.name"."table.name"
|
152
30
|
def quote_table_name(name)
|
153
|
-
|
154
|
-
|
155
|
-
unless name_part
|
156
|
-
quote_column_name(schema)
|
157
|
-
else
|
158
|
-
table_name, name_part = extract_pg_identifier_from_name(name_part)
|
159
|
-
"#{quote_column_name(schema)}.#{quote_column_name(table_name)}"
|
160
|
-
end
|
31
|
+
Utils.extract_schema_qualified_name(name.to_s).quoted
|
161
32
|
end
|
162
33
|
|
163
34
|
def quote_table_name_for_assignment(table, attr)
|
@@ -177,11 +48,60 @@ module ActiveRecord
|
|
177
48
|
result = "#{result}.#{sprintf("%06d", value.usec)}"
|
178
49
|
end
|
179
50
|
|
180
|
-
if value.year
|
181
|
-
|
51
|
+
if value.year <= 0
|
52
|
+
bce_year = format("%04d", -value.year + 1)
|
53
|
+
result = result.sub(/^-?\d+/, bce_year) + " BC"
|
182
54
|
end
|
183
55
|
result
|
184
56
|
end
|
57
|
+
|
58
|
+
# Does not quote function default values for UUID columns
|
59
|
+
def quote_default_value(value, column) #:nodoc:
|
60
|
+
if column.type == :uuid && value =~ /\(\)/
|
61
|
+
value
|
62
|
+
else
|
63
|
+
quote(value, column)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
def _quote(value)
|
70
|
+
case value
|
71
|
+
when Type::Binary::Data
|
72
|
+
"'#{escape_bytea(value.to_s)}'"
|
73
|
+
when OID::Xml::Data
|
74
|
+
"xml '#{quote_string(value.to_s)}'"
|
75
|
+
when OID::Bit::Data
|
76
|
+
if value.binary?
|
77
|
+
"B'#{value}'"
|
78
|
+
elsif value.hex?
|
79
|
+
"X'#{value}'"
|
80
|
+
end
|
81
|
+
when Float
|
82
|
+
if value.infinite? || value.nan?
|
83
|
+
"'#{value}'"
|
84
|
+
else
|
85
|
+
super
|
86
|
+
end
|
87
|
+
else
|
88
|
+
super
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def _type_cast(value)
|
93
|
+
case value
|
94
|
+
when Type::Binary::Data
|
95
|
+
# Return a bind param hash with format as binary.
|
96
|
+
# See http://deveiate.org/code/pg/PGconn.html#method-i-exec_prepared-doc
|
97
|
+
# for more information
|
98
|
+
{ value: value.to_s, format: 1 }
|
99
|
+
when OID::Xml::Data, OID::Bit::Data
|
100
|
+
value.to_s
|
101
|
+
else
|
102
|
+
super
|
103
|
+
end
|
104
|
+
end
|
185
105
|
end
|
186
106
|
end
|
187
107
|
end
|
@@ -1,12 +1,12 @@
|
|
1
1
|
module ActiveRecord
|
2
2
|
module ConnectionAdapters
|
3
|
-
|
4
|
-
module ReferentialIntegrity
|
5
|
-
def supports_disable_referential_integrity?
|
3
|
+
module PostgreSQL
|
4
|
+
module ReferentialIntegrity # :nodoc:
|
5
|
+
def supports_disable_referential_integrity? # :nodoc:
|
6
6
|
true
|
7
7
|
end
|
8
8
|
|
9
|
-
def disable_referential_integrity
|
9
|
+
def disable_referential_integrity # :nodoc:
|
10
10
|
if supports_disable_referential_integrity?
|
11
11
|
begin
|
12
12
|
execute(tables.collect { |name| "ALTER TABLE #{quote_table_name(name)} DISABLE TRIGGER ALL" }.join(";"))
|