activerecord 5.0.0.beta3 → 5.0.0.beta4
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 +225 -8
- data/examples/performance.rb +0 -1
- data/examples/simple.rb +0 -1
- data/lib/active_record.rb +0 -1
- data/lib/active_record/associations.rb +10 -6
- data/lib/active_record/associations/association.rb +1 -1
- data/lib/active_record/associations/builder/collection_association.rb +5 -1
- data/lib/active_record/associations/join_dependency.rb +1 -1
- data/lib/active_record/associations/preloader.rb +1 -0
- data/lib/active_record/associations/preloader/through_association.rb +15 -8
- data/lib/active_record/attribute/user_provided_default.rb +10 -5
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +1 -1
- data/lib/active_record/attributes.rb +3 -3
- data/lib/active_record/autosave_association.rb +1 -1
- data/lib/active_record/base.rb +2 -1
- data/lib/active_record/collection_cache_key.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +0 -19
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +7 -8
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/quoting.rb +7 -1
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +16 -2
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +9 -4
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +20 -10
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +85 -20
- data/lib/active_record/connection_adapters/abstract/transaction.rb +13 -1
- data/lib/active_record/connection_adapters/abstract_adapter.rb +37 -16
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +119 -108
- data/lib/active_record/connection_adapters/column.rb +5 -6
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +125 -0
- data/lib/active_record/connection_adapters/mysql/quoting.rb +51 -0
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +27 -6
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +8 -13
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +18 -55
- data/lib/active_record/connection_adapters/postgresql/column.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +4 -4
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +7 -10
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +65 -25
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +59 -30
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +48 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +7 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +19 -56
- data/lib/active_record/connection_adapters/statement_pool.rb +6 -4
- data/lib/active_record/core.rb +13 -4
- data/lib/active_record/enum.rb +1 -1
- data/lib/active_record/errors.rb +9 -0
- data/lib/active_record/fixture_set/file.rb +7 -1
- data/lib/active_record/gem_version.rb +1 -1
- data/lib/active_record/locking/optimistic.rb +4 -0
- data/lib/active_record/log_subscriber.rb +1 -1
- data/lib/active_record/migration.rb +4 -4
- data/lib/active_record/migration/compatibility.rb +1 -1
- data/lib/active_record/model_schema.rb +12 -0
- data/lib/active_record/nested_attributes.rb +1 -1
- data/lib/active_record/persistence.rb +1 -1
- data/lib/active_record/query_cache.rb +13 -16
- data/lib/active_record/querying.rb +1 -1
- data/lib/active_record/railtie.rb +8 -11
- data/lib/active_record/railties/databases.rake +5 -5
- data/lib/active_record/reflection.rb +21 -4
- data/lib/active_record/relation.rb +10 -10
- data/lib/active_record/relation/batches.rb +29 -9
- data/lib/active_record/relation/delegation.rb +0 -1
- data/lib/active_record/relation/finder_methods.rb +27 -8
- data/lib/active_record/relation/predicate_builder.rb +4 -2
- data/lib/active_record/relation/where_clause.rb +2 -1
- data/lib/active_record/schema_dumper.rb +39 -24
- data/lib/active_record/scoping/default.rb +2 -1
- data/lib/active_record/suppressor.rb +5 -1
- data/lib/active_record/tasks/database_tasks.rb +6 -4
- data/lib/active_record/tasks/mysql_database_tasks.rb +1 -1
- data/lib/active_record/type.rb +1 -1
- data/lib/active_record/type/internal/abstract_json.rb +1 -5
- data/lib/active_record/type/time.rb +12 -0
- data/lib/active_record/validations/uniqueness.rb +1 -4
- data/lib/rails/generators/active_record/model/model_generator.rb +15 -11
- data/lib/rails/generators/active_record/model/templates/application_record.rb +2 -0
- metadata +11 -8
@@ -27,8 +27,8 @@ module ActiveRecord
|
|
27
27
|
# - schema_name."table.name"
|
28
28
|
# - "schema.name".table_name
|
29
29
|
# - "schema.name"."table.name"
|
30
|
-
def quote_table_name(name)
|
31
|
-
Utils.extract_schema_qualified_name(name.to_s).quoted
|
30
|
+
def quote_table_name(name) # :nodoc:
|
31
|
+
@quoted_table_names[name] ||= Utils.extract_schema_qualified_name(name.to_s).quoted
|
32
32
|
end
|
33
33
|
|
34
34
|
# Quotes schema names for use in SQL queries.
|
@@ -41,8 +41,8 @@ module ActiveRecord
|
|
41
41
|
end
|
42
42
|
|
43
43
|
# Quotes column names for use in SQL queries.
|
44
|
-
def quote_column_name(name)
|
45
|
-
PGconn.quote_ident(
|
44
|
+
def quote_column_name(name) # :nodoc:
|
45
|
+
@quoted_column_names[name] ||= PGconn.quote_ident(super)
|
46
46
|
end
|
47
47
|
|
48
48
|
# Quote date/time values for use in SQL input.
|
@@ -3,16 +3,9 @@ module ActiveRecord
|
|
3
3
|
module PostgreSQL
|
4
4
|
module ColumnDumper
|
5
5
|
def column_spec_for_primary_key(column)
|
6
|
-
spec =
|
7
|
-
if column
|
8
|
-
|
9
|
-
spec[:id] = ':bigserial'
|
10
|
-
elsif column.type == :uuid
|
11
|
-
spec[:id] = ':uuid'
|
12
|
-
spec[:default] = schema_default(column) || 'nil'
|
13
|
-
else
|
14
|
-
spec[:id] = schema_type(column).inspect
|
15
|
-
spec.merge!(prepare_column_options(column).delete_if { |key, _| [:name, :type, :null].include?(key) })
|
6
|
+
spec = super
|
7
|
+
if schema_type(column) == :uuid
|
8
|
+
spec[:default] ||= 'nil'
|
16
9
|
end
|
17
10
|
spec
|
18
11
|
end
|
@@ -31,6 +24,10 @@ module ActiveRecord
|
|
31
24
|
|
32
25
|
private
|
33
26
|
|
27
|
+
def default_primary_key?(column)
|
28
|
+
schema_type(column) == :serial
|
29
|
+
end
|
30
|
+
|
34
31
|
def schema_type(column)
|
35
32
|
return super unless column.serial?
|
36
33
|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'active_support/core_ext/string/strip'
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
module ConnectionAdapters
|
3
5
|
module PostgreSQL
|
@@ -172,7 +174,11 @@ module ActiveRecord
|
|
172
174
|
table = Utils.extract_schema_qualified_name(table_name.to_s)
|
173
175
|
|
174
176
|
result = query(<<-SQL, 'SCHEMA')
|
175
|
-
SELECT distinct i.relname, d.indisunique, d.indkey, pg_get_indexdef(d.indexrelid), t.oid
|
177
|
+
SELECT distinct i.relname, d.indisunique, d.indkey, pg_get_indexdef(d.indexrelid), t.oid,
|
178
|
+
pg_catalog.obj_description(i.oid, 'pg_class') AS comment,
|
179
|
+
(SELECT COUNT(*) FROM pg_opclass o
|
180
|
+
JOIN (SELECT unnest(string_to_array(d.indclass::text, ' '))::int oid) c
|
181
|
+
ON o.oid = c.oid WHERE o.opcdefault = 'f')
|
176
182
|
FROM pg_class t
|
177
183
|
INNER JOIN pg_index d ON t.oid = d.indrelid
|
178
184
|
INNER JOIN pg_class i ON d.indexrelid = i.oid
|
@@ -190,43 +196,61 @@ module ActiveRecord
|
|
190
196
|
indkey = row[2].split(" ").map(&:to_i)
|
191
197
|
inddef = row[3]
|
192
198
|
oid = row[4]
|
199
|
+
comment = row[5]
|
200
|
+
opclass = row[6]
|
193
201
|
|
194
|
-
|
195
|
-
SELECT a.attnum, a.attname
|
196
|
-
FROM pg_attribute a
|
197
|
-
WHERE a.attrelid = #{oid}
|
198
|
-
AND a.attnum IN (#{indkey.join(",")})
|
199
|
-
SQL
|
202
|
+
using, expressions, where = inddef.scan(/ USING (\w+?) \((.+?)\)(?: WHERE (.+))?\z/).flatten
|
200
203
|
|
201
|
-
|
204
|
+
if indkey.include?(0) || opclass > 0
|
205
|
+
columns = expressions
|
206
|
+
else
|
207
|
+
columns = Hash[query(<<-SQL.strip_heredoc, "SCHEMA")].values_at(*indkey).compact
|
208
|
+
SELECT a.attnum, a.attname
|
209
|
+
FROM pg_attribute a
|
210
|
+
WHERE a.attrelid = #{oid}
|
211
|
+
AND a.attnum IN (#{indkey.join(",")})
|
212
|
+
SQL
|
202
213
|
|
203
|
-
unless column_names.empty?
|
204
214
|
# add info on sort order for columns (only desc order is explicitly specified, asc is the default)
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
using = inddef.scan(/USING (.+?) /).flatten[0].to_sym
|
209
|
-
|
210
|
-
IndexDefinition.new(table_name, index_name, unique, column_names, [], orders, where, nil, using)
|
215
|
+
orders = Hash[
|
216
|
+
expressions.scan(/(\w+) DESC/).flatten.map { |order_column| [order_column, :desc] }
|
217
|
+
]
|
211
218
|
end
|
219
|
+
|
220
|
+
IndexDefinition.new(table_name, index_name, unique, columns, [], orders, where, nil, using.to_sym, comment)
|
212
221
|
end.compact
|
213
222
|
end
|
214
223
|
|
215
224
|
# Returns the list of all column definitions for a table.
|
216
|
-
def columns(table_name)
|
217
|
-
|
218
|
-
column_definitions(table_name).map do |column_name, type, default, notnull, oid, fmod, collation|
|
225
|
+
def columns(table_name) # :nodoc:
|
226
|
+
table_name = table_name.to_s
|
227
|
+
column_definitions(table_name).map do |column_name, type, default, notnull, oid, fmod, collation, comment|
|
219
228
|
oid = oid.to_i
|
220
229
|
fmod = fmod.to_i
|
221
230
|
type_metadata = fetch_type_metadata(column_name, type, oid, fmod)
|
222
231
|
default_value = extract_value_from_default(default)
|
223
232
|
default_function = extract_default_function(default_value, default)
|
224
|
-
new_column(column_name, default_value, type_metadata, !notnull, default_function, collation)
|
233
|
+
new_column(column_name, default_value, type_metadata, !notnull, table_name, default_function, collation, comment: comment.presence)
|
225
234
|
end
|
226
235
|
end
|
227
236
|
|
228
|
-
def new_column(
|
229
|
-
PostgreSQLColumn.new(
|
237
|
+
def new_column(*args) # :nodoc:
|
238
|
+
PostgreSQLColumn.new(*args)
|
239
|
+
end
|
240
|
+
|
241
|
+
# Returns a comment stored in database for given table
|
242
|
+
def table_comment(table_name) # :nodoc:
|
243
|
+
name = Utils.extract_schema_qualified_name(table_name.to_s)
|
244
|
+
if name.identifier
|
245
|
+
select_value(<<-SQL.strip_heredoc, 'SCHEMA')
|
246
|
+
SELECT pg_catalog.obj_description(c.oid, 'pg_class')
|
247
|
+
FROM pg_catalog.pg_class c
|
248
|
+
LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
|
249
|
+
WHERE c.relname = #{quote(name.identifier)}
|
250
|
+
AND c.relkind IN ('r') -- (r)elation/table
|
251
|
+
AND n.nspname = #{name.schema ? quote(name.schema) : 'ANY (current_schemas(false))'}
|
252
|
+
SQL
|
253
|
+
end
|
230
254
|
end
|
231
255
|
|
232
256
|
# Returns the current database name.
|
@@ -325,7 +349,7 @@ module ActiveRecord
|
|
325
349
|
|
326
350
|
select_value("SELECT setval('#{quoted_sequence}', #{value})", 'SCHEMA')
|
327
351
|
else
|
328
|
-
@logger.warn "#{table} has primary key #{pk} with no default sequence" if @logger
|
352
|
+
@logger.warn "#{table} has primary key #{pk} with no default sequence." if @logger
|
329
353
|
end
|
330
354
|
end
|
331
355
|
end
|
@@ -340,7 +364,7 @@ module ActiveRecord
|
|
340
364
|
end
|
341
365
|
|
342
366
|
if @logger && pk && !sequence
|
343
|
-
@logger.warn "#{table} has primary key #{pk} with no default sequence"
|
367
|
+
@logger.warn "#{table} has primary key #{pk} with no default sequence."
|
344
368
|
end
|
345
369
|
|
346
370
|
if pk && sequence
|
@@ -445,6 +469,7 @@ module ActiveRecord
|
|
445
469
|
def add_column(table_name, column_name, type, options = {}) #:nodoc:
|
446
470
|
clear_cache!
|
447
471
|
super
|
472
|
+
change_column_comment(table_name, column_name, options[:comment]) if options.key?(:comment)
|
448
473
|
end
|
449
474
|
|
450
475
|
def change_column(table_name, column_name, type, options = {}) #:nodoc:
|
@@ -466,6 +491,7 @@ module ActiveRecord
|
|
466
491
|
|
467
492
|
change_column_default(table_name, column_name, options[:default]) if options_include_default?(options)
|
468
493
|
change_column_null(table_name, column_name, options[:null], options[:default]) if options.key?(:null)
|
494
|
+
change_column_comment(table_name, column_name, options[:comment]) if options.key?(:comment)
|
469
495
|
end
|
470
496
|
|
471
497
|
# Changes the default value of a table column.
|
@@ -494,6 +520,18 @@ module ActiveRecord
|
|
494
520
|
execute("ALTER TABLE #{quote_table_name(table_name)} ALTER #{quote_column_name(column_name)} #{null ? 'DROP' : 'SET'} NOT NULL")
|
495
521
|
end
|
496
522
|
|
523
|
+
# Adds comment for given table column or drops it if +comment+ is a +nil+
|
524
|
+
def change_column_comment(table_name, column_name, comment) # :nodoc:
|
525
|
+
clear_cache!
|
526
|
+
execute "COMMENT ON COLUMN #{quote_table_name(table_name)}.#{quote_column_name(column_name)} IS #{quote(comment)}"
|
527
|
+
end
|
528
|
+
|
529
|
+
# Adds comment for given table or drops it if +comment+ is a +nil+
|
530
|
+
def change_table_comment(table_name, comment) # :nodoc:
|
531
|
+
clear_cache!
|
532
|
+
execute "COMMENT ON TABLE #{quote_table_name(table_name)} IS #{quote(comment)}"
|
533
|
+
end
|
534
|
+
|
497
535
|
# Renames a column in a table.
|
498
536
|
def rename_column(table_name, column_name, new_column_name) #:nodoc:
|
499
537
|
clear_cache!
|
@@ -502,8 +540,10 @@ module ActiveRecord
|
|
502
540
|
end
|
503
541
|
|
504
542
|
def add_index(table_name, column_name, options = {}) #:nodoc:
|
505
|
-
index_name, index_type, index_columns, index_options, index_algorithm, index_using = add_index_options(table_name, column_name, options)
|
506
|
-
execute
|
543
|
+
index_name, index_type, index_columns, index_options, index_algorithm, index_using, comment = add_index_options(table_name, column_name, options)
|
544
|
+
execute("CREATE #{index_type} INDEX #{index_algorithm} #{quote_column_name(index_name)} ON #{quote_table_name(table_name)} #{index_using} (#{index_columns})#{index_options}").tap do
|
545
|
+
execute "COMMENT ON INDEX #{quote_column_name(index_name)} IS #{quote(comment)}" if comment
|
546
|
+
end
|
507
547
|
end
|
508
548
|
|
509
549
|
def remove_index(table_name, options = {}) #:nodoc:
|
@@ -16,8 +16,6 @@ require "active_record/connection_adapters/postgresql/type_metadata"
|
|
16
16
|
require "active_record/connection_adapters/postgresql/utils"
|
17
17
|
require "active_record/connection_adapters/statement_pool"
|
18
18
|
|
19
|
-
require 'ipaddr'
|
20
|
-
|
21
19
|
module ActiveRecord
|
22
20
|
module ConnectionHandling # :nodoc:
|
23
21
|
# Establishes a connection to the database that's used by all Active Record objects
|
@@ -119,12 +117,15 @@ module ActiveRecord
|
|
119
117
|
include PostgreSQL::SchemaStatements
|
120
118
|
include PostgreSQL::DatabaseStatements
|
121
119
|
include PostgreSQL::ColumnDumper
|
122
|
-
include Savepoints
|
123
120
|
|
124
121
|
def schema_creation # :nodoc:
|
125
122
|
PostgreSQL::SchemaCreation.new self
|
126
123
|
end
|
127
124
|
|
125
|
+
def arel_visitor # :nodoc:
|
126
|
+
Arel::Visitors::PostgreSQL.new(self)
|
127
|
+
end
|
128
|
+
|
128
129
|
# Returns true, since this connection adapter supports prepared statement
|
129
130
|
# caching.
|
130
131
|
def supports_statement_cache?
|
@@ -139,6 +140,10 @@ module ActiveRecord
|
|
139
140
|
true
|
140
141
|
end
|
141
142
|
|
143
|
+
def supports_expression_index?
|
144
|
+
true
|
145
|
+
end
|
146
|
+
|
142
147
|
def supports_transaction_isolation?
|
143
148
|
true
|
144
149
|
end
|
@@ -159,6 +164,18 @@ module ActiveRecord
|
|
159
164
|
postgresql_version >= 90200
|
160
165
|
end
|
161
166
|
|
167
|
+
def supports_comments?
|
168
|
+
true
|
169
|
+
end
|
170
|
+
|
171
|
+
def supports_comments_in_create?
|
172
|
+
false
|
173
|
+
end
|
174
|
+
|
175
|
+
def supports_savepoints?
|
176
|
+
true
|
177
|
+
end
|
178
|
+
|
162
179
|
def index_algorithms
|
163
180
|
{ concurrently: 'CONCURRENTLY' }
|
164
181
|
end
|
@@ -195,14 +212,6 @@ module ActiveRecord
|
|
195
212
|
def initialize(connection, logger, connection_parameters, config)
|
196
213
|
super(connection, logger, config)
|
197
214
|
|
198
|
-
@visitor = Arel::Visitors::PostgreSQL.new self
|
199
|
-
if self.class.type_cast_config_to_boolean(config.fetch(:prepared_statements) { true })
|
200
|
-
@prepared_statements = true
|
201
|
-
@visitor.extend(DetermineIfPreparableVisitor)
|
202
|
-
else
|
203
|
-
@prepared_statements = false
|
204
|
-
end
|
205
|
-
|
206
215
|
@connection_parameters = connection_parameters
|
207
216
|
|
208
217
|
# @local_tz is initialized as nil to avoid warnings when connect tries to use it
|
@@ -212,7 +221,7 @@ module ActiveRecord
|
|
212
221
|
connect
|
213
222
|
add_pg_encoders
|
214
223
|
@statements = StatementPool.new @connection,
|
215
|
-
self.class.type_cast_config_to_integer(config
|
224
|
+
self.class.type_cast_config_to_integer(config[:statement_limit])
|
216
225
|
|
217
226
|
if postgresql_version < 90100
|
218
227
|
raise "Your version of PostgreSQL (#{postgresql_version}) is too old. Active Record supports PostgreSQL >= 9.1."
|
@@ -398,6 +407,7 @@ module ActiveRecord
|
|
398
407
|
protected
|
399
408
|
|
400
409
|
# See http://www.postgresql.org/docs/current/static/errcodes-appendix.html
|
410
|
+
VALUE_LIMIT_VIOLATION = "22001"
|
401
411
|
FOREIGN_KEY_VIOLATION = "23503"
|
402
412
|
UNIQUE_VIOLATION = "23505"
|
403
413
|
|
@@ -409,6 +419,8 @@ module ActiveRecord
|
|
409
419
|
RecordNotUnique.new(message)
|
410
420
|
when FOREIGN_KEY_VIOLATION
|
411
421
|
InvalidForeignKey.new(message)
|
422
|
+
when VALUE_LIMIT_VIOLATION
|
423
|
+
ValueTooLong.new(message)
|
412
424
|
else
|
413
425
|
super
|
414
426
|
end
|
@@ -598,25 +610,41 @@ module ActiveRecord
|
|
598
610
|
@connection.exec_prepared(stmt_key, type_casted_binds)
|
599
611
|
end
|
600
612
|
rescue ActiveRecord::StatementInvalid => e
|
601
|
-
|
613
|
+
raise unless is_cached_plan_failure?(e)
|
602
614
|
|
603
|
-
#
|
604
|
-
#
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
rescue
|
610
|
-
raise e
|
611
|
-
end
|
612
|
-
if FEATURE_NOT_SUPPORTED == code
|
615
|
+
# Nothing we can do if we are in a transaction because all commands
|
616
|
+
# will raise InFailedSQLTransaction
|
617
|
+
if in_transaction?
|
618
|
+
raise ActiveRecord::PreparedStatementCacheExpired.new(e.cause.message)
|
619
|
+
else
|
620
|
+
# outside of transactions we can simply flush this query and retry
|
613
621
|
@statements.delete sql_key(sql)
|
614
622
|
retry
|
615
|
-
else
|
616
|
-
raise e
|
617
623
|
end
|
618
624
|
end
|
619
625
|
|
626
|
+
# Annoyingly, the code for prepared statements whose return value may
|
627
|
+
# have changed is FEATURE_NOT_SUPPORTED.
|
628
|
+
#
|
629
|
+
# This covers various different error types so we need to do additional
|
630
|
+
# work to classify the exception definitively as a
|
631
|
+
# ActiveRecord::PreparedStatementCacheExpired
|
632
|
+
#
|
633
|
+
# Check here for more details:
|
634
|
+
# http://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/backend/utils/cache/plancache.c#l573
|
635
|
+
CACHED_PLAN_HEURISTIC = 'cached plan must not change result type'.freeze
|
636
|
+
def is_cached_plan_failure?(e)
|
637
|
+
pgerror = e.cause
|
638
|
+
code = pgerror.result.result_error_field(PGresult::PG_DIAG_SQLSTATE)
|
639
|
+
code == FEATURE_NOT_SUPPORTED && pgerror.message.include?(CACHED_PLAN_HEURISTIC)
|
640
|
+
rescue
|
641
|
+
false
|
642
|
+
end
|
643
|
+
|
644
|
+
def in_transaction?
|
645
|
+
open_transactions > 0
|
646
|
+
end
|
647
|
+
|
620
648
|
# Returns the statement identifier for the client side cache
|
621
649
|
# of statements
|
622
650
|
def sql_key(sql)
|
@@ -696,7 +724,7 @@ module ActiveRecord
|
|
696
724
|
# Returns the list of a table's column names, data types, and default values.
|
697
725
|
#
|
698
726
|
# The underlying query is roughly:
|
699
|
-
# SELECT column.name, column.type, default.value
|
727
|
+
# SELECT column.name, column.type, default.value, column.comment
|
700
728
|
# FROM column LEFT JOIN default
|
701
729
|
# ON column.table_id = default.table_id
|
702
730
|
# AND column.num = default.column_num
|
@@ -716,7 +744,8 @@ module ActiveRecord
|
|
716
744
|
SELECT a.attname, format_type(a.atttypid, a.atttypmod),
|
717
745
|
pg_get_expr(d.adbin, d.adrelid), a.attnotnull, a.atttypid, a.atttypmod,
|
718
746
|
(SELECT c.collname FROM pg_collation c, pg_type t
|
719
|
-
WHERE c.oid = a.attcollation AND t.oid = a.atttypid AND a.attcollation <> t.typcollation)
|
747
|
+
WHERE c.oid = a.attcollation AND t.oid = a.atttypid AND a.attcollation <> t.typcollation),
|
748
|
+
col_description(a.attrelid, a.attnum) AS comment
|
720
749
|
FROM pg_attribute a LEFT JOIN pg_attrdef d
|
721
750
|
ON a.attrelid = d.adrelid AND a.attnum = d.adnum
|
722
751
|
WHERE a.attrelid = '#{quote_table_name(table_name)}'::regclass
|
@@ -730,8 +759,8 @@ module ActiveRecord
|
|
730
759
|
$1.strip if $1
|
731
760
|
end
|
732
761
|
|
733
|
-
def create_table_definition(
|
734
|
-
PostgreSQL::TableDefinition.new(
|
762
|
+
def create_table_definition(*args) # :nodoc:
|
763
|
+
PostgreSQL::TableDefinition.new(*args)
|
735
764
|
end
|
736
765
|
|
737
766
|
def can_perform_case_insensitive_comparison_for?(column)
|
@@ -799,7 +828,7 @@ module ActiveRecord
|
|
799
828
|
ActiveRecord::Type.register(:bit_varying, OID::BitVarying, adapter: :postgresql)
|
800
829
|
ActiveRecord::Type.register(:binary, OID::Bytea, adapter: :postgresql)
|
801
830
|
ActiveRecord::Type.register(:cidr, OID::Cidr, adapter: :postgresql)
|
802
|
-
ActiveRecord::Type.register(:
|
831
|
+
ActiveRecord::Type.register(:datetime, OID::DateTime, adapter: :postgresql)
|
803
832
|
ActiveRecord::Type.register(:decimal, OID::Decimal, adapter: :postgresql)
|
804
833
|
ActiveRecord::Type.register(:enum, OID::Enum, adapter: :postgresql)
|
805
834
|
ActiveRecord::Type.register(:hstore, OID::Hstore, adapter: :postgresql)
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module ConnectionAdapters
|
3
|
+
module SQLite3
|
4
|
+
module Quoting # :nodoc:
|
5
|
+
def quote_string(s)
|
6
|
+
@connection.class.quote(s)
|
7
|
+
end
|
8
|
+
|
9
|
+
def quote_table_name_for_assignment(table, attr)
|
10
|
+
quote_column_name(attr)
|
11
|
+
end
|
12
|
+
|
13
|
+
def quote_column_name(name)
|
14
|
+
@quoted_column_names[name] ||= %Q("#{super.gsub('"', '""')}")
|
15
|
+
end
|
16
|
+
|
17
|
+
def quoted_time(value)
|
18
|
+
quoted_date(value)
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def _quote(value)
|
24
|
+
if value.is_a?(Type::Binary::Data)
|
25
|
+
"x'#{value.hex}'"
|
26
|
+
else
|
27
|
+
super
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def _type_cast(value)
|
32
|
+
case value
|
33
|
+
when BigDecimal
|
34
|
+
value.to_f
|
35
|
+
when String
|
36
|
+
if value.encoding == Encoding::ASCII_8BIT
|
37
|
+
super(value.encode(Encoding::UTF_8))
|
38
|
+
else
|
39
|
+
super
|
40
|
+
end
|
41
|
+
else
|
42
|
+
super
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|