123456789_123456789_123456789_123456789_123456789_

Module: ActiveRecord::ConnectionAdapters::PostgreSQL::ReferentialIntegrity

Do not use. This module is for internal use only.
Relationships & Source Files
Extension / Inclusion / Inheritance Descendants
Included In:
Defined in: activerecord/lib/active_record/connection_adapters/postgresql/referential_integrity.rb

Instance Method Summary

Instance Method Details

#check_all_foreign_keys_valid!

[ GitHub ]

  
# File 'activerecord/lib/active_record/connection_adapters/postgresql/referential_integrity.rb', line 71

def check_all_foreign_keys_valid! # :nodoc:
  # Skip `NOT ENFORCED` constraints (PG 18.4+): `VALIDATE CONSTRAINT` cannot be
  # applied to them and raises an error.
  if supports_enforced_foreign_keys?
    enforced_join = <<~SQL
      JOIN pg_catalog.pg_constraint c
        ON c.conname = tc.constraint_name
       AND c.conenforced = true
      JOIN pg_catalog.pg_class cls ON cls.oid = c.conrelid
       AND cls.relname = tc.table_name
      JOIN pg_catalog.pg_namespace ns ON ns.oid = cls.relnamespace
       AND ns.nspname = tc.table_schema
       AND ns.nspname = tc.constraint_schema
    SQL
  end

  sql = <<~SQL
    do $$
      declare r record;
    BEGIN
    FOR r IN (
      SELECT FORMAT(
        'UPDATE pg_catalog.pg_constraint SET convalidated=false WHERE conname = ''%1$I'' AND connamespace::regnamespace = ''%2$I''::regnamespace AND conrelid::regclass = ''%3$I''::regclass; ALTER TABLE %2$I.%3$I VALIDATE CONSTRAINT %1$I;',
        constraint_name,
        table_schema,
        table_name
      ) AS constraint_check
      FROM information_schema.table_constraints tc
      #{enforced_join}
      WHERE tc.constraint_type = 'FOREIGN KEY'
    )
      LOOP
        EXECUTE (r.constraint_check);
      END LOOP;
    END;
    $$;
  SQL

  transaction(requires_new: true) do
    execute(sql)
  end
end

#disable_referential_integrity

[ GitHub ]

  
# File 'activerecord/lib/active_record/connection_adapters/postgresql/referential_integrity.rb', line 7

def disable_referential_integrity # :nodoc:
  if supports_enforced_foreign_keys?
    # Only toggle FKs that are currently `ENFORCED`; leave `NOT ENFORCED` ones unchanged.
    # `conparentid = 0` excludes constraints inherited from a partitioned parent —
    # `ALTER CONSTRAINT` must be issued on the parent and is propagated to partitions.
    enforced_fks = query_all(<<~SQL)
      SELECT n.nspname AS schema_name, t.relname AS table_name, c.conname AS constraint_name
      FROM pg_constraint c
      JOIN pg_class t ON c.conrelid = t.oid
      JOIN pg_namespace n ON c.connamespace = n.oid
      WHERE c.contype = 'f'
        AND c.conenforced = true
        AND c.conparentid = 0
        AND n.nspname = ANY (current_schemas(false))
    SQL

    transaction(requires_new: true) do
      enforced_fks.each do |fk|
        execute("ALTER TABLE #{quote_table_name(fk["schema_name"])}.#{quote_table_name(fk["table_name"])} " \
                "ALTER CONSTRAINT #{quote_column_name(fk["constraint_name"])} NOT ENFORCED")
      end

      yield

      enforced_fks.each do |fk|
        execute("ALTER TABLE #{quote_table_name(fk["schema_name"])}.#{quote_table_name(fk["table_name"])} " \
                "ALTER CONSTRAINT #{quote_column_name(fk["constraint_name"])} ENFORCED")
      end
    end
  else
    original_exception = nil

    begin
      transaction(requires_new: true) do
        execute(tables.collect { |name| "ALTER TABLE #{quote_table_name(name)} DISABLE TRIGGER ALL" }.join(";"))
      end
    rescue ActiveRecord::ActiveRecordError => e
      original_exception = e
    end

    begin
      yield
    rescue ActiveRecord::InvalidForeignKey => e
      warn <<~WARNING
        WARNING: Rails was not able to disable referential integrity.

        This is most likely caused due to missing permissions.
        The user must be superuser to execute DISABLE TRIGGER ALL.

            cause: #{original_exception&.message}

      WARNING
      raise e
    end

    begin
      transaction(requires_new: true) do
        execute(tables.collect { |name| "ALTER TABLE #{quote_table_name(name)} ENABLE TRIGGER ALL" }.join(";"))
      end
    rescue ActiveRecord::ActiveRecordError
    end
  end
end