Skip to content

Commit

Permalink
Merge pull request rails#49504 from fatkodima/fix-pg-retrieving-ident…
Browse files Browse the repository at this point in the history
…ity-columns

Fix auto populating `IDENTITY` columns for PostgreSQL
  • Loading branch information
byroot authored Oct 9, 2023
2 parents f11c651 + f592d50 commit 7b1bdbb
Show file tree
Hide file tree
Showing 5 changed files with 33 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,24 @@ module PostgreSQL
class Column < ConnectionAdapters::Column # :nodoc:
delegate :oid, :fmod, to: :sql_type_metadata

def initialize(*, serial: nil, generated: nil, **)
def initialize(*, serial: nil, identity: nil, generated: nil, **)
super
@serial = serial
@identity = identity
@generated = generated
end

def identity?
@identity
end

def serial?
@serial
end
alias_method :auto_incremented_by_db?, :serial?

def auto_incremented_by_db?
serial? || identity?
end

def virtual?
# We assume every generated column is virtual, no matter the concrete type
Expand All @@ -41,26 +49,30 @@ def sql_type

def init_with(coder)
@serial = coder["serial"]
@identity = coder["identity"]
@generated = coder["generated"]
super
end

def encode_with(coder)
coder["serial"] = @serial
coder["identity"] = @identity
coder["generated"] = @generated
super
end

def ==(other)
other.is_a?(Column) &&
super &&
identity? == other.identity? &&
serial? == other.serial?
end
alias :eql? :==

def hash
Column.hash ^
super.hash ^
identity?.hash ^
serial?.hash
end
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -908,7 +908,7 @@ def create_alter_table(name)
end

def new_column_from_field(table_name, field, _definitions)
column_name, type, default, notnull, oid, fmod, collation, comment, attgenerated = field
column_name, type, default, notnull, oid, fmod, collation, comment, identity, attgenerated = field
type_metadata = fetch_type_metadata(column_name, type, oid.to_i, fmod.to_i)
default_value = extract_value_from_default(default)

Expand All @@ -931,6 +931,7 @@ def new_column_from_field(table_name, field, _definitions)
collation: collation,
comment: comment.presence,
serial: serial,
identity: identity.presence,
generated: attgenerated
)
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1084,6 +1084,7 @@ def column_definitions(table_name)
SELECT a.attname, format_type(a.atttypid, a.atttypmod),
pg_get_expr(d.adbin, d.adrelid), a.attnotnull, a.atttypid, a.atttypmod,
c.collname, col_description(a.attrelid, a.attnum) AS comment,
a.attidentity AS identity,
#{supports_virtual_columns? ? 'attgenerated' : quote('')} as attgenerated
FROM pg_attribute a
LEFT JOIN pg_attrdef d ON a.attrelid = d.adrelid AND a.attnum = d.adnum
Expand Down
9 changes: 9 additions & 0 deletions activerecord/test/cases/persistence_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,15 @@ def test_fills_auto_populated_columns_on_creation
assert_not_nil record_with_defaults.modified_time
assert_not_nil record_with_defaults.modified_time_without_precision
assert_not_nil record_with_defaults.modified_time_function

if current_adapter?(:PostgreSQLAdapter)
klass = Class.new(ActiveRecord::Base) do
self.table_name = "postgresql_identity_table"
end

record = klass.create!
assert_not_nil record.id
end
end if current_adapter?(:PostgreSQLAdapter) || current_adapter?(:SQLite3Adapter)

def test_update_many
Expand Down
7 changes: 7 additions & 0 deletions activerecord/test/schema/postgresql_specific_schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,13 @@
"
end

drop_table "postgresql_identity_table", if_exists: true
execute <<~SQL
create table postgresql_identity_table (
id INT PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY
)
SQL

create_table :postgresql_times, force: true do |t|
t.interval :time_interval
t.interval :scaled_time_interval, precision: 6
Expand Down

0 comments on commit 7b1bdbb

Please sign in to comment.