rails-sqlserver/activerecord-sqlserver-adapter

String default value not retrieved when using views

budiljak opened this issue · 4 comments

Issue

When using a view pointing to a string column, the sqlserver-adapter doesn't retrieve the default value. Instead the value is nil. This leads to a ActiveRecord::NotNullViolation if the record is saved without explicitly assigning a value to the corresponding attribute.

  • Rails version: 7.0.4
  • SQL Server adapter version: 7.0.4
  • TinyTDS version: 2.1.5

Script to reproduce the bug:

require "bundler/inline"

gemfile(true) do
  source "https://rubygems.org"
  gem "tiny_tds"

  gem "activerecord", "=7.0.4.2"
  gem "activerecord-sqlserver-adapter", git: "https://github.com/rails-sqlserver/activerecord-sqlserver-adapter", ref: "0be80a6565f56c984a74ff11abc2e52dbbae50e2"
  #gem "activerecord-sqlserver-adapter", "=7.0.4"
  #gem "activerecord-sqlserver-adapter", "7.0.3"
end

require "active_record"
require "minitest/autorun"
require "logger"

ActiveRecord::Base.establish_connection(
  adapter:  "sqlserver",
  timeout:  5000,
  pool:     100,
  encoding: "utf8",
  database: "test_database",
  username: "SA",
  password: "StrongPassword!",
  host:     "localhost",
  port:     1433,
)
ActiveRecord::Base.logger = Logger.new(STDOUT)

ActiveRecord::Schema.define do
  drop_table :bug_test_tables rescue nil

  create_table :bug_test_tables, force: true do |t|
    t.boolean :Bool_field, null: false, default: false
    t.string :string_field, null: false, default: "abc"
  end
  drop_view = "DROP VIEW IF EXISTS bug_tests;"
  create_view = "CREATE VIEW bug_tests AS SELECT id AS id, bool_field AS b, string_field as s FROM bug_test_tables"
  ActiveRecord::Base.connection.execute(drop_view)
  ActiveRecord::Base.connection.execute(create_view)
end

class BugTest < ActiveRecord::Base
end

class TestBugTest < Minitest::Test
  def setup
    # IMPORTANT: partial_inserts is false by default since Rails 7.0
    # without that ActiveRecord will not try to infer default values
    # before creating the record and hence there's no error
    ActiveRecord::Base.partial_inserts = false
    @bug_test = BugTest.new
  end

  
  def test_default_value
    assert_equal false, @bug_test.b
    assert_equal "abc", @bug_test.s
    @bug_test.save!
    assert_equal 1, BugTest.count
  end
end

Hi @budiljak, this issue has been fixed by #1126 and is in release v7.0.5.0

Thanks for your efforts! :-)

Hi @aidanharan,

unfortunately it seems like there's new bugs when retrieving the default values. If the default for a datetime column is added by a constraint statement the default is falsely retrieved as "1970-1-1 00:00:00".

The error occurs if the NULL-Default is added like this:

ALTER TABLE [dbo].[XXX] ADD CONSTRAINT [DEFULT_FOR_TEST] DEFAULT (NULL) FOR [test];

And: I have one string column without any default for which the default is retrieved as "0".

:-(

Hi @budiljak, would you be able to open a new issue about the date issue and include a script to reproduce it? I had a look and wasn't able to recreate it.