Skip to content

Commit 76eab08

Browse files
committed
Support VIRTUAL generated columns on PostgreSQL 18+ using :virtual option
PostgreSQL 18+ made the default VIRTUAL if not specified. This doesn't break backwards compatibility, as STORED was required previously. Unfortunately, making VIRTUAL the default in Sequel would break backwards compatibility. So in Sequel, the default will remain to have STORED as the default, and require the :virtual option to use VIRTUAL.
1 parent 9c264ef commit 76eab08

File tree

5 files changed

+24
-1
lines changed

5 files changed

+24
-1
lines changed

CHANGELOG

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
=== master
2+
3+
* Support VIRTUAL generated columns on PostgreSQL 18+ using :virtual option (jeremyevans)
4+
15
=== 5.95.1 (2025-08-05)
26

37
* Fix regression in 5.95.0 where :deferred would be ignored for unique and primary key constraints on PostgreSQL (jeremyevans) (#2321)

lib/sequel/adapters/shared/postgres.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1291,7 +1291,7 @@ def column_definition_default_sql(sql, column)
12911291
sql << (identity == :always ? "ALWAYS" : "BY DEFAULT")
12921292
sql << " AS IDENTITY"
12931293
elsif (generated = column[:generated_always_as])
1294-
sql << " GENERATED ALWAYS AS (#{literal(generated)}) STORED"
1294+
sql << " GENERATED ALWAYS AS (#{literal(generated)}) #{column[:virtual] ? 'VIRTUAL' : 'STORED'}"
12951295
end
12961296
end
12971297
end

lib/sequel/database/schema_generator.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,9 @@ def check(*args, &block)
156156
# PostgreSQL specific options:
157157
#
158158
# :identity :: Create an identity column.
159+
# :virtual :: When using :generated_always_as, create a VIRTUAL column instead of a STORED
160+
# column (PostgreSQL 18+). VIRTUAL is the default if not specified on
161+
# PostgreSQL 18+, but for backwards compatibility, Sequel's default is STORED.
159162
#
160163
# MySQL specific options:
161164
#

spec/adapters/postgres_spec.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -740,6 +740,12 @@ def c.exec_prepared(*); super; nil end
740740
@db[:tmp_dolls].select_order_map([:a, :b, :c]).must_equal [[100, 10, 211]]
741741
end if DB.server_version >= 120000
742742

743+
it "should support creating generated virtual columns" do
744+
@db.create_table(:tmp_dolls){Integer :a; Integer :b; Integer :c, :generated_always_as=>Sequel[:a] * 2 + :b + 1, :virtual=>true}
745+
@db[:tmp_dolls].insert(:a=>100, :b=>10)
746+
@db[:tmp_dolls].select_order_map([:a, :b, :c]).must_equal [[100, 10, 211]]
747+
end if DB.server_version >= 180000
748+
743749
it "should include :generated entry in schema for whether the column is generated" do
744750
@db.create_table(:tmp_dolls){Integer :a; Integer :b; Integer :c, :generated_always_as=>Sequel[:a] * 2 + :b + 1}
745751
@db.schema(:tmp_dolls).map{|_,v| v[:generated]}.must_equal [false, false, true]

spec/core/mock_adapter_spec.rb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -886,6 +886,16 @@ def @db.regclass_oid(x) 1234 end
886886
]
887887
end
888888

889+
it "should default generated columns to STORED" do
890+
@db.create_table(:t){Integer :c, :generated_always_as=>Sequel[:t] + 1}
891+
@db.sqls.must_equal ['CREATE TABLE "t" ("c" integer GENERATED ALWAYS AS (("t" + 1)) STORED)']
892+
end
893+
894+
it "should create VIRTUAL generated columns if given :virtual option" do
895+
@db.create_table(:t){Integer :c, :generated_always_as=>Sequel[:t] + 1, :virtual=>true}
896+
@db.sqls.must_equal ['CREATE TABLE "t" ("c" integer GENERATED ALWAYS AS (("t" + 1)) VIRTUAL)']
897+
end
898+
889899
it "should not support converting serial columns to identity on PostgreSQL <10.2" do
890900
def @db.server_version; 100000; end
891901
proc{@db.convert_serial_to_identity(:table)}.must_raise Sequel::Error

0 commit comments

Comments
 (0)