c5a69a1d9baa3444ac16a3ddd12895bb5b399f26
[rails.git] / config / initializers / postgresql_adapter.rb
1 module ActiveRecord
2   module ConnectionAdapters
3     class PostgreSQLAdapter
4       def pk_and_sequence_for(table)
5         # First try looking for a sequence with a dependency on the
6         # given table's primary key.
7         result = query(<<-end_sql, 'PK and serial sequence')[0]
8           SELECT attr.attname, seq.relname
9           FROM pg_class      seq,
10                pg_attribute  attr,
11                pg_depend     dep,
12                pg_namespace  name,
13                pg_constraint cons
14           WHERE seq.oid           = dep.objid
15             AND seq.relkind       = 'S'
16             AND attr.attrelid     = dep.refobjid
17             AND attr.attnum       = dep.refobjsubid
18             AND attr.attrelid     = cons.conrelid
19             AND attr.attnum       = cons.conkey[1]
20             AND cons.contype      = 'p'
21             AND dep.classid       = '"pg_class"'::regclass
22             AND dep.refclassid    = '"pg_class"'::regclass
23             AND dep.refobjid      = '#{quote_table_name(table)}'::regclass
24         end_sql
25
26         if result.nil? or result.empty?
27           # If that fails, try parsing the primary key's default value.
28           # Support the 7.x and 8.0 nextval('foo'::text) as well as
29           # the 8.1+ nextval('foo'::regclass).
30           result = query(<<-end_sql, 'PK and custom sequence')[0]
31             SELECT attr.attname,
32               CASE
33                 WHEN split_part(def.adsrc, '''', 2) ~ '.' THEN
34                   substr(split_part(def.adsrc, '''', 2),
35                          strpos(split_part(def.adsrc, '''', 2), '.')+1)
36                 ELSE split_part(def.adsrc, '''', 2)
37               END
38             FROM pg_class       t
39             JOIN pg_attribute   attr ON (t.oid = attrelid)
40             JOIN pg_attrdef     def  ON (adrelid = attrelid AND adnum = attnum)
41             JOIN pg_constraint  cons ON (conrelid = adrelid AND adnum = conkey[1])
42             WHERE t.oid = '#{quote_table_name(table)}'::regclass
43               AND cons.contype = 'p'
44               AND def.adsrc ~* 'nextval'
45           end_sql
46         end
47
48         # [primary_key, sequence]
49         [result.first, result.last]
50       rescue
51         nil
52       end
53     end
54   end
55 end