1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
|
# frozen-string-literal: true
#
# The pg_schema_caching extension builds on top of the schema_caching
# extension, and allows it to handle custom PostgreSQL types. On
# PostgreSQL, column schema hashes include an :oid entry for the OID
# for the column's type. For custom types, this OID is dependent on
# the PostgreSQL database, so in most cases, test and development
# versions of the same database, created with the same migrations,
# will have different OIDs.
#
# To fix this case, the pg_schema_caching extension removes custom
# OIDs from the schema cache when dumping the schema, replacing them
# with a placeholder. When loading the cached schema, the Database
# object makes a single query to get the OIDs for all custom types
# used by the cached schema, and it updates all related column
# schema hashes to set the correct :oid entry for the current
# database.
#
# Related module: Sequel::Postgres::SchemaCaching
require_relative "schema_caching"
module Sequel
module Postgres
module SchemaCaching
include Sequel::SchemaCaching
private
# Load custom oids from database when loading schema cache file.
def load_schema_cache_file(file)
set_custom_oids_for_cached_schema(super)
end
# Find all column schema hashes that use custom types.
# Load the oids for custom types in a single query, and update
# each related column schema hash with the correct oid.
def set_custom_oids_for_cached_schema(schemas)
custom_oid_rows = {}
schemas.each_value do |cols|
cols.each do |_, h|
if h[:oid] == :custom
(custom_oid_rows[h[:db_type]] ||= []) << h
end
end
end
unless custom_oid_rows.empty?
from(:pg_type).where(:typname=>custom_oid_rows.keys).select_hash(:typname, :oid).each do |name, oid|
custom_oid_rows.delete(name).each do |row|
row[:oid] = oid
end
end
end
unless custom_oid_rows.empty?
warn "Could not load OIDs for the following custom types: #{custom_oid_rows.keys.sort.join(", ")}", uplevel: 3
schemas.keys.each do |k|
if schemas[k].any?{|_,h| h[:oid] == :custom}
# Remove schema entry for table, so it will be queried at runtime to get the correct oids
schemas.delete(k)
end
end
end
schemas
end
# Replace :oid entries for custom types with :custom.
def dumpable_schema_cache
sch = super
sch.each_value do |cols|
cols.each do |_, h|
if (oid = h[:oid]) && oid >= 10000
h[:oid] = :custom
end
end
end
sch
end
end
end
Database.register_extension(:pg_schema_caching, Postgres::SchemaCaching)
end
|