@@ -32,6 +32,115 @@ def primary_key(table_name)
3232 end
3333 end
3434
35+ def primary_keys ( table_name )
36+ return super unless database_version >= 24_02_02
37+
38+ query_values ( <<~SQL , "SCHEMA" )
39+ SELECT a.attname
40+ FROM (
41+ SELECT indrelid, indkey, generate_subscripts(indkey, 1) idx
42+ FROM pg_index
43+ WHERE indrelid = #{ quote ( quote_table_name ( table_name ) ) } ::regclass
44+ AND indisprimary
45+ ) i
46+ JOIN pg_attribute a
47+ ON a.attrelid = i.indrelid
48+ AND a.attnum = i.indkey[i.idx]
49+ AND NOT a.attishidden
50+ ORDER BY i.idx
51+ SQL
52+ end
53+
54+ def column_names_from_column_numbers ( table_oid , column_numbers )
55+ return super unless database_version >= 24_02_02
56+
57+ Hash [ query ( <<~SQL , "SCHEMA" ) ] . values_at ( *column_numbers ) . compact
58+ SELECT a.attnum, a.attname
59+ FROM pg_attribute a
60+ WHERE a.attrelid = #{ table_oid }
61+ AND a.attnum IN (#{ column_numbers . join ( ", " ) } )
62+ AND NOT a.attishidden
63+ SQL
64+ end
65+
66+ # OVERRIDE: CockroachDB does not support deferrable constraints.
67+ # See: https://go.crdb.dev/issue-v/31632/v23.1
68+ def foreign_key_options ( from_table , to_table , options )
69+ options = super
70+ options . delete ( :deferrable ) unless supports_deferrable_constraints?
71+ options
72+ end
73+
74+ # OVERRIDE: Added `unique_rowid` to the last line of the second query.
75+ # This is a CockroachDB-specific function used for primary keys.
76+ # Also make sure we don't consider `NOT VISIBLE` columns.
77+ #
78+ # Returns a table's primary key and belonging sequence.
79+ def pk_and_sequence_for ( table ) # :nodoc:
80+ # First try looking for a sequence with a dependency on the
81+ # given table's primary key.
82+ result = query ( <<~SQL , "SCHEMA" ) [ 0 ]
83+ SELECT attr.attname, nsp.nspname, seq.relname
84+ FROM pg_class seq,
85+ pg_attribute attr,
86+ pg_depend dep,
87+ pg_constraint cons,
88+ pg_namespace nsp,
89+ -- TODO: use the pg_catalog.pg_attribute(attishidden) column when
90+ -- it is added instead of joining on crdb_internal.
91+ -- See https://github.com/cockroachdb/cockroach/pull/126397
92+ crdb_internal.table_columns tc
93+ WHERE seq.oid = dep.objid
94+ AND seq.relkind = 'S'
95+ AND attr.attrelid = dep.refobjid
96+ AND attr.attnum = dep.refobjsubid
97+ AND attr.attrelid = cons.conrelid
98+ AND attr.attnum = cons.conkey[1]
99+ AND seq.relnamespace = nsp.oid
100+ AND attr.attrelid = tc.descriptor_id
101+ AND attr.attname = tc.column_name
102+ AND tc.hidden = false
103+ AND cons.contype = 'p'
104+ AND dep.classid = 'pg_class'::regclass
105+ AND dep.refobjid = #{ quote ( quote_table_name ( table ) ) } ::regclass
106+ SQL
107+
108+ if result . nil? || result . empty?
109+ result = query ( <<~SQL , "SCHEMA" ) [ 0 ]
110+ SELECT attr.attname, nsp.nspname,
111+ CASE
112+ WHEN pg_get_expr(def.adbin, def.adrelid) !~* 'nextval' THEN NULL
113+ WHEN split_part(pg_get_expr(def.adbin, def.adrelid), '''', 2) ~ '.' THEN
114+ substr(split_part(pg_get_expr(def.adbin, def.adrelid), '''', 2),
115+ strpos(split_part(pg_get_expr(def.adbin, def.adrelid), '''', 2), '.')+1)
116+ ELSE split_part(pg_get_expr(def.adbin, def.adrelid), '''', 2)
117+ END
118+ FROM pg_class t
119+ JOIN pg_attribute attr ON (t.oid = attrelid)
120+ JOIN pg_attrdef def ON (adrelid = attrelid AND adnum = attnum)
121+ JOIN pg_constraint cons ON (conrelid = adrelid AND adnum = conkey[1])
122+ JOIN pg_namespace nsp ON (t.relnamespace = nsp.oid)
123+ -- TODO: use the pg_catalog.pg_attribute(attishidden) column when
124+ -- it is added instead of joining on crdb_internal.
125+ -- See https://github.com/cockroachdb/cockroach/pull/126397
126+ JOIN crdb_internal.table_columns tc ON (attr.attrelid = tc.descriptor_id AND attr.attname = tc.column_name)
127+ WHERE t.oid = #{ quote ( quote_table_name ( table ) ) } ::regclass
128+ AND tc.hidden = false
129+ AND cons.contype = 'p'
130+ AND pg_get_expr(def.adbin, def.adrelid) ~* 'nextval|uuid_generate|gen_random_uuid|unique_rowid'
131+ SQL
132+ end
133+
134+ pk = result . shift
135+ if result . last
136+ [ pk , PostgreSQL ::Name . new ( *result ) ]
137+ else
138+ [ pk , nil ]
139+ end
140+ rescue
141+ nil
142+ end
143+
35144 # override
36145 # Modified version of the postgresql foreign_keys method.
37146 # Replaces t2.oid::regclass::text with t2.relname since this is
0 commit comments