WITH columns AS (SELECT nspname AS table_schema, relname AS table_name,
attname AS column_name,
CASE WHEN typbasetype=0 THEN pg_type.typname
ELSE (SELECT typname
FROM pg_type AS domain_type
WHERE domain_type.oid=pg_type.typbasetype) END AS column_type,
CASE WHEN attndims<>0 OR typndims<>0 THEN TRUE ELSE FALSE END AS is_array
FROM pg_class INNER JOIN pg_namespace ON pg_class.relnamespace=pg_namespace.oid
INNER JOIN pg_attribute ON pg_class.oid=pg_attribute.attrelid
INNER JOIN pg_type ON pg_attribute.atttypid =pg_type.oid
WHERE attnum>=1
AND relkind ='r'
AND nspname NOT IN (SELECT schema_name
FROM INFORMATION_SCHEMA.schemata
WHERE schema_name<>'public' AND
schema_owner='postgres' AND schema_name IS NOT NULL)),
plural_singular AS (SELECT table_schema, table_name, column_name,
CASE WHEN is_array=FALSE THEN column_type ELSE 'ARRAY [' || translate(column_type,'_','') || ']' END AS column_type,
CASE WHEN regexp_replace(column_name,'(stats_|stats$|status|state|is_|has_|pos$|alias|cvs|address|value$|key$|pays$|group$|lock$|_to$|_id$|_code$|_type$|_name$|posts_to|sales_tax|trans_type|_date$|_time$|_flag$|number|sys|class$|basis$)','','g') ~* '(?<!((^|_)[[:alnum:]]{0,2}|(^|_)[bcdfghjklmnpqrsztvwxz]{0,4}|s))s(_|$)' THEN 'Perhaps plural' ELSE 'Perhaps singular' END AS comment_about_the_column_name
FROM columns),
fk as (select
o.conname,
(select nspname from pg_namespace where oid=f.relnamespace) as foreign_schema,
f.relname as foreign_table,
f.oid as foreign_table_oid,
o.confkey AS foreign_col,
(select nspname from pg_namespace where oid=c.relnamespace) as target_schema,
c.relname as target_table,
c.oid as target_table_oid,
o.conkey AS target_col
from pg_constraint o inner join pg_class c on c.oid = o.conrelid
inner join pg_class f on f.oid = o.confrelid
where o.contype = 'f'
and cardinality(o.conkey)=1),
fk_unnest as (select conname, foreign_schema, foreign_table, foreign_table_oid, foreign_col, foreign_col_num, target_schema, target_table, target_table_oid, target_col, target_col_num, ordin
from fk, unnest(fk.foreign_col, fk. target_col) with ordinality as f(foreign_col_num, target_col_num, ordin)),
fk_with_names as (select conname, foreign_schema, foreign_table, a_foreign.attname as foreign_col, target_schema, target_table, a_target.attname as target_col
from fk_unnest fk inner join pg_attribute a_foreign on fk.foreign_col_num = a_foreign.attnum and fk.foreign_table_oid = a_foreign.attrelid and a_foreign.attisdropped = false
inner join pg_attribute a_target on fk.target_col_num = a_target.attnum and fk.target_table_oid = a_target.attrelid and a_target.attisdropped = false)
select conname, foreign_schema, foreign_table, foreign_col, psf.comment_about_the_column_name AS foreign_comment,
target_schema, target_table, target_col, pst.comment_about_the_column_name AS target_comment
from fk_with_names AS fwn INNER JOIN plural_singular AS psf ON fwn.foreign_schema=psf.table_schema AND fwn.foreign_table=psf.table_name AND fwn.foreign_col=psf.column_name
INNER JOIN plural_singular AS pst ON fwn.target_schema=pst.table_schema AND fwn.target_table=pst.table_name AND fwn.target_col=pst.column_name
WHERE psf.comment_about_the_column_name<>pst.comment_about_the_column_name
order by target_schema, target_table, conname;