Fix view column source detection

This commit is contained in:
Ruslan Talpa
2016-02-29 13:10:33 +02:00
parent 62af792add
commit 40a30d7b02
2 changed files with 89 additions and 61 deletions
+88 -60
View File
@@ -556,69 +556,97 @@ allSynonyms :: [Column] -> H.Query () [(Column,Column)]
allSynonyms cols = allSynonyms cols =
H.statement sql HE.unit (decodeSynonyms cols) True H.statement sql HE.unit (decodeSynonyms cols) True
where where
-- query explanation at https://gist.github.com/ruslantalpa/2eab8c930a65e8043d8f
sql = [q| sql = [q|
WITH synonyms AS ( WITH view_columns AS (
/* SELECT
-- CTE to replace the view from information_schema because the information in it depended on the logged in role c.oid AS view_oid,
-- notice the commented line nc.nspname::information_schema.sql_identifier AS view_schema,
*/ c.relname::information_schema.sql_identifier AS view_name,
WITH view_column_usage AS ( a.attname::information_schema.sql_identifier AS column_name
SELECT DISTINCT FROM pg_attribute a
CAST(current_database() AS character varying) AS view_catalog, JOIN (pg_class c JOIN pg_namespace nc ON c.relnamespace = nc.oid) ON a.attrelid = c.oid
CAST(nv.nspname AS character varying) AS view_schema, WHERE
CAST(v.relname AS character varying) AS view_name, NOT pg_is_other_temp_schema(nc.oid)
CAST(current_database() AS character varying) AS table_catalog, AND a.attnum > 0
CAST(nt.nspname AS character varying) AS table_schema, AND NOT a.attisdropped
CAST(t.relname AS character varying) AS table_name, AND (c.relkind = 'v'::"char")
CAST(a.attname AS character varying) AS column_name AND nc.nspname NOT IN ('information_schema', 'pg_catalog')
FROM pg_namespace nv, pg_class v, pg_depend dv, ),
pg_depend dt, pg_class t, pg_namespace nt,
pg_attribute a view_column_usage AS (
WHERE nv.oid = v.relnamespace SELECT DISTINCT
AND v.relkind = 'v' v.oid as view_oid,
AND v.oid = dv.refobjid nv.nspname::information_schema.sql_identifier AS view_schema,
AND dv.refclassid = 'pg_catalog.pg_class'::regclass v.relname::information_schema.sql_identifier AS view_name,
AND dv.classid = 'pg_catalog.pg_rewrite'::regclass nt.nspname::information_schema.sql_identifier AS table_schema,
AND dv.deptype = 'i' t.relname::information_schema.sql_identifier AS table_name,
AND dv.objid = dt.objid a.attname::information_schema.sql_identifier AS column_name,
AND dv.refobjid <> dt.refobjid pg_get_viewdef(v.oid)::information_schema.character_data AS view_definition
AND dt.classid = 'pg_catalog.pg_rewrite'::regclass FROM
AND dt.refclassid = 'pg_catalog.pg_class'::regclass pg_namespace nv,
AND dt.refobjid = t.oid pg_class v,
AND t.relnamespace = nt.oid pg_depend dv,
AND t.relkind IN ('r', 'v', 'f') pg_depend dt,
AND t.oid = a.attrelid pg_class t,
AND dt.refobjsubid = a.attnum pg_namespace nt,
/*--AND pg_has_role(t.relowner, 'USAGE')*/ pg_attribute a
) WHERE
SELECT nv.oid = v.relnamespace
vcu.table_schema AS src_table_schema, AND nv.nspname not in ('information_schema', 'pg_catalog')
vcu.table_name AS src_table_name, AND v.relkind = 'v'::"char"
vcu.column_name AS src_column_name, AND v.oid = dv.refobjid
view.schemaname AS syn_table_schema, AND dv.refclassid = 'pg_class'::regclass::oid
view.viewname AS syn_table_name, AND dv.classid = 'pg_rewrite'::regclass::oid
view.definition AS view_definition AND dv.deptype = 'i'::"char"
FROM AND dv.objid = dt.objid
pg_catalog.pg_views AS view, AND dv.refobjid <> dt.refobjid
view_column_usage AS vcu AND dt.classid = 'pg_rewrite'::regclass::oid
WHERE AND dt.refclassid = 'pg_class'::regclass::oid
view.schemaname = vcu.view_schema AND AND dt.refobjid = t.oid
view.viewname = vcu.view_name AND AND t.relnamespace = nt.oid
view.schemaname NOT IN ('pg_catalog', 'information_schema') AND (t.relkind = ANY (ARRAY['r'::"char", 'v'::"char", 'f'::"char"]))
/*--AND (SELECT COUNT(*) FROM information_schema.view_table_usage WHERE view_schema = view.schemaname AND view_name = view.viewname) = 1*/ AND t.oid = a.attrelid
AND dt.refobjsubid = a.attnum
),
candidates AS (
(
SELECT
vcu.*,
(REGEXP_MATCHES(
CONCAT('SELECT ', SPLIT_PART(vcu.view_definition, 'SELECT', 2)),
CONCAT('SELECT.*?((',vcu.table_name,')|(\w+))\.(', vcu.column_name, ')(\sAS\s(")?([^"]+)\6)?.*?FROM.*?',vcu.table_schema,'\.(\2|',vcu.table_name,'\s+(AS\s)?\3)'),
'ns'
))[7] AS view_column_name
FROM view_column_usage AS vcu
)
UNION
(
SELECT
vcu.*,
(REGEXP_MATCHES(
CONCAT('SELECT ', SPLIT_PART(vcu.view_definition, 'SELECT', 2)),
CONCAT('SELECT.*?((',vcu.table_name,')|(\w+))\.(', vcu.column_name, ')(\sAS\s(")?([^"]+)\6)?.*?FROM.*?',vcu.table_schema,'\.(\2|',vcu.table_name,'\s+(AS\s)?\3)'),
'ns'
))[4] AS view_column_name
FROM view_column_usage AS vcu
)
) )
SELECT SELECT
src_table_schema, src_table_name, src_column_name, c.table_schema,
syn_table_schema, syn_table_name, c.table_name,
(regexp_matches(view_definition, CONCAT('\.(', src_column_name, ')(?=,|$)'), 'gn'))[1] AS syn_column_name c.column_name AS table_column_name,
FROM synonyms c.view_schema,
UNION ( c.view_name,
SELECT c.view_column_name
src_table_schema, src_table_name, src_column_name, FROM view_columns AS vc, candidates AS c
syn_table_schema, syn_table_name, WHERE
(regexp_matches(view_definition, CONCAT('\.', src_column_name, '\sAS\s("?)(.+?)\1(,|$)'), 'gn'))[2] AS syn_column_name /* " <- for syntax highlighting */ vc.view_oid = c.view_oid AND
FROM synonyms vc.column_name = c.view_column_name
) |] ORDER BY c.view_schema, c.view_name, c.table_name, c.view_column_name
|]
synonymFromRow :: [Column] -> (Text,Text,Text,Text,Text,Text) -> Maybe (Column,Column) synonymFromRow :: [Column] -> (Text,Text,Text,Text,Text,Text) -> Maybe (Column,Column)
synonymFromRow allCols (s1,t1,c1,s2,t2,c2) = (,) <$> col1 <*> col2 synonymFromRow allCols (s1,t1,c1,s2,t2,c2) = (,) <$> col1 <*> col2
+1 -1
View File
@@ -9,7 +9,7 @@ extra-deps:
- postgresql-error-codes-1 - postgresql-error-codes-1
- postgresql-binary-0.8.1 - postgresql-binary-0.8.1
ghc-options: ghc-options:
postgrest: -O1 -Werror -Wall -fwarn-monomorphism-restriction -fwarn-missing-exported-sigs -fwarn-identities postgrest: -O2 -Werror -Wall -fwarn-monomorphism-restriction -fwarn-missing-exported-sigs -fwarn-identities
packages: packages:
- '.' - '.'