diff --git a/CHANGELOG b/CHANGELOG index 1b53ae59e6..1a8e1460ec 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,7 @@ +=== master + +* Support :generated_always_as column option on PostgreSQL 12+ (jeremyevans) + === 5.23.0 (2019-08-01) * Work around a bug on jdbc-sqlite3 3.27.2.1 when parsing schema for tables with columns with default values (jeremyevans) diff --git a/lib/sequel/adapters/shared/postgres.rb b/lib/sequel/adapters/shared/postgres.rb index 8abb43c8d9..46132113c6 100644 --- a/lib/sequel/adapters/shared/postgres.rb +++ b/lib/sequel/adapters/shared/postgres.rb @@ -836,10 +836,14 @@ def column_definition_collate_sql(sql, column) # default value is given. def column_definition_default_sql(sql, column) super - if !column[:serial] && !['serial', 'bigserial'].include?(column[:type].to_s) && !column[:default] && (identity = column[:identity]) - sql << " GENERATED " - sql << (identity == :always ? "ALWAYS" : "BY DEFAULT") - sql << " AS IDENTITY" + if !column[:serial] && !['serial', 'bigserial'].include?(column[:type].to_s) && !column[:default] + if (identity = column[:identity]) + sql << " GENERATED " + sql << (identity == :always ? "ALWAYS" : "BY DEFAULT") + sql << " AS IDENTITY" + elsif (generated = column[:generated_always_as]) + sql << " GENERATED ALWAYS AS (#{literal(generated)}) STORED" + end end end diff --git a/lib/sequel/database/schema_generator.rb b/lib/sequel/database/schema_generator.rb index 36de900193..27b95bdfb3 100644 --- a/lib/sequel/database/schema_generator.rb +++ b/lib/sequel/database/schema_generator.rb @@ -110,6 +110,9 @@ def check(*args, &block) # yet exist on referenced table (but will exist before the transaction commits). # Basically it adds DEFERRABLE INITIALLY DEFERRED on key creation. # If you use :immediate as the value, uses DEFERRABLE INITIALLY IMMEDIATE. + # :generated_always_as :: Specify a GENERATED ALWAYS AS column expression, + # if generated columns are supported (PostgreSQL 12+, MariaDB 5.2.0+, + # and MySQL 5.7.6+). # :index :: Create an index on this column. If given a hash, use the hash as the # options for the index. # :key :: For foreign key columns, the column in the associated table @@ -132,9 +135,11 @@ def check(*args, &block) # creating a unique index on the column. # :unique_constraint_name :: The name to give the unique key constraint # + # PostgreSQL specific options: + # + # :identity :: Create an identity column. + # # MySQL specific options: - # :generated_always_as :: Specify a GENERATED ALWAYS AS column expression, - # if generated columns are supported. # :generated_type :: Set the type of column when using :generated_always_as, # should be :virtual or :stored to force a type. def column(name, type, opts = OPTS) diff --git a/spec/adapters/postgres_spec.rb b/spec/adapters/postgres_spec.rb index bd74ac8184..0a7f949aa9 100644 --- a/spec/adapters/postgres_spec.rb +++ b/spec/adapters/postgres_spec.rb @@ -227,6 +227,12 @@ @db.convert_serial_to_identity(:tmp_dolls, :column=>:id) end if DB.server_version >= 100002 && DB.get{current_setting('is_superuser')} == 'on' + it "should support creating generated columns" do + @db.create_table(:tmp_dolls){Integer :a; Integer :b; Integer :c, :generated_always_as=>Sequel[:a] * 2 + :b + 1} + @db[:tmp_dolls].insert(:a=>100, :b=>10) + @db[:tmp_dolls].select_order_map([:a, :b, :c]).must_equal [[100, 10, 211]] + end if DB.server_version >= 120000 + it "should support pg_loose_count extension" do @db.extension :pg_loose_count @db.create_table(:tmp_dolls){text :name}