@@ -32,6 +32,115 @@ def primary_key(table_name)
32
32
end
33
33
end
34
34
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
+
35
144
# override
36
145
# Modified version of the postgresql foreign_keys method.
37
146
# Replaces t2.oid::regclass::text with t2.relname since this is
0 commit comments