Fix #1182, fix subselect view embedding for pg10

This commit is contained in:
steve-chavez
2018-10-12 09:24:22 -05:00
committed by Steve Chávez
parent b48824bddd
commit dc834572d6
6 changed files with 84 additions and 81 deletions
+1 -2
View File
@@ -5,12 +5,11 @@ module Main where
import PostgREST.App (postgrest) import PostgREST.App (postgrest)
import PostgREST.Config (AppConfig (..), import PostgREST.Config (AppConfig (..),
minimumPgVersion,
prettyVersion, readOptions) prettyVersion, readOptions)
import PostgREST.DbStructure (getDbStructure, getPgVersion) import PostgREST.DbStructure (getDbStructure, getPgVersion)
import PostgREST.Error (encodeError) import PostgREST.Error (encodeError)
import PostgREST.OpenAPI (isMalformedProxyUri) import PostgREST.OpenAPI (isMalformedProxyUri)
import PostgREST.Types (DbStructure, Schema, PgVersion(..)) import PostgREST.Types (DbStructure, Schema, PgVersion(..), minimumPgVersion)
import Protolude hiding (hPutStrLn, replace) import Protolude hiding (hPutStrLn, replace)
+1 -14
View File
@@ -18,9 +18,6 @@ module PostgREST.Config ( prettyVersion
, docsVersion , docsVersion
, readOptions , readOptions
, corsPolicy , corsPolicy
, minimumPgVersion
, pgVersion95
, pgVersion96
, AppConfig (..) , AppConfig (..)
) )
where where
@@ -52,7 +49,7 @@ import Network.Wai.Middleware.Cors (CorsResourcePolicy (..))
import Options.Applicative hiding (str) import Options.Applicative hiding (str)
import Paths_postgrest (version) import Paths_postgrest (version)
import PostgREST.Parsers (pRoleClaimKey) import PostgREST.Parsers (pRoleClaimKey)
import PostgREST.Types (PgVersion(..), ApiRequestError(..), import PostgREST.Types (ApiRequestError(..),
JSPath, JSPathExp(..)) JSPath, JSPathExp(..))
import Protolude hiding (hPutStrLn, take, import Protolude hiding (hPutStrLn, take,
intercalate, (<>)) intercalate, (<>))
@@ -233,13 +230,3 @@ pathParser =
strArgument $ strArgument $
metavar "FILENAME" <> metavar "FILENAME" <>
help "Path to configuration file" help "Path to configuration file"
-- | Tells the minimum PostgreSQL version required by this version of PostgREST
minimumPgVersion :: PgVersion
minimumPgVersion = PgVersion 90400 "9.4"
pgVersion96 :: PgVersion
pgVersion96 = PgVersion 90600 "9.6"
pgVersion95 :: PgVersion
pgVersion95 = PgVersion 90500 "9.5"
+64 -61
View File
@@ -26,7 +26,7 @@ import Data.Text (split, strip,
import qualified Data.Text as T import qualified Data.Text as T
import qualified Hasql.Session as H import qualified Hasql.Session as H
import PostgREST.Types import PostgREST.Types
import Text.InterpolatedString.Perl6 (q) import Text.InterpolatedString.Perl6 (q, qc)
import GHC.Exts (groupWith) import GHC.Exts (groupWith)
import Protolude import Protolude
@@ -36,7 +36,7 @@ getDbStructure :: Schema -> PgVersion -> H.Session DbStructure
getDbStructure schema pgVer = do getDbStructure schema pgVer = do
tabs <- H.statement () allTables tabs <- H.statement () allTables
cols <- H.statement schema $ allColumns tabs cols <- H.statement schema $ allColumns tabs
syns <- H.statement schema $ allSynonyms cols syns <- H.statement schema $ allSynonyms cols pgVer
childRels <- H.statement () $ allChildRelations tabs cols childRels <- H.statement () $ allChildRelations tabs cols
keys <- H.statement () $ allPrimaryKeys tabs keys <- H.statement () $ allPrimaryKeys tabs
procs <- H.statement schema allProcs procs <- H.statement schema allProcs
@@ -685,68 +685,71 @@ pkFromRow :: [Table] -> (Schema, Text, Text) -> Maybe PrimaryKey
pkFromRow tabs (s, t, n) = PrimaryKey <$> table <*> pure n pkFromRow tabs (s, t, n) = PrimaryKey <$> table <*> pure n
where table = find (\tbl -> tableSchema tbl == s && tableName tbl == t) tabs where table = find (\tbl -> tableSchema tbl == s && tableName tbl == t) tabs
allSynonyms :: [Column] -> H.Statement Schema [Synonym] allSynonyms :: [Column] -> PgVersion -> H.Statement Schema [Synonym]
allSynonyms cols = allSynonyms cols pgVer =
H.Statement sql (HE.param HE.text) (decodeSynonyms cols) True H.Statement sql (HE.param HE.text) (decodeSynonyms cols) True
-- query explanation at https://gist.github.com/steve-chavez/7ee0e6590cddafb532e5f00c46275569 -- query explanation at https://gist.github.com/steve-chavez/7ee0e6590cddafb532e5f00c46275569
where sql = [q| where
with subselectRegex :: Text
views as ( subselectRegex | pgVer < pgVersion100 = ":subselect {.*?:constraintDeps <>} :location"
| otherwise = ":subselect {.*?:stmt_len 0} :location"
sql = [qc|
with
views as (
select
n.nspname as view_schema,
c.relname as view_name,
r.ev_action as view_definition
from pg_class c
join pg_namespace n on n.oid = c.relnamespace
join pg_rewrite r on r.ev_class = c.oid
where (c.relkind = 'v'::char) and n.nspname = $1
),
removed_subselects as(
select
view_schema, view_name,
regexp_replace(view_definition, '{subselectRegex}', '', 'g') as x
from views
),
target_lists as(
select
view_schema, view_name,
regexp_split_to_array(x, 'targetList') as x
from removed_subselects
),
last_target_list_wo_tail as(
select
view_schema, view_name,
(regexp_split_to_array(x[array_upper(x, 1)], ':onConflict'))[1] as x
from target_lists
),
target_entries as(
select
view_schema, view_name,
unnest(regexp_split_to_array(x, 'TARGETENTRY')) as entry
from last_target_list_wo_tail
),
results as(
select
view_schema, view_name,
substring(entry from ':resname (.*?) :') as view_colum_name,
substring(entry from ':resorigtbl (.*?) :') as resorigtbl,
substring(entry from ':resorigcol (.*?) :') as resorigcol
from target_entries
)
select select
n.nspname as view_schema, sch.nspname as table_schema,
c.relname as view_name, tbl.relname as table_name,
r.ev_action as view_definition col.attname as table_column_name,
from pg_class c res.view_schema,
join pg_namespace n on n.oid = c.relnamespace res.view_name,
join pg_rewrite r on r.ev_class = c.oid res.view_colum_name
where (c.relkind = 'v'::char) and n.nspname = $1 from results res
), join pg_class tbl on tbl.oid::text = res.resorigtbl
removed_subselects as( join pg_attribute col on col.attrelid = tbl.oid and col.attnum::text = res.resorigcol
select join pg_namespace sch on sch.oid = tbl.relnamespace
view_schema, view_name, where resorigtbl <> '0'
regexp_replace(view_definition, ':subselect {.*?:constraintDeps <>} :location', '', 'g') as x order by view_schema, view_name, view_colum_name; |]
from views
),
target_lists as(
select
view_schema, view_name,
regexp_split_to_array(x, 'targetList') as x
from removed_subselects
),
last_target_list_wo_tail as(
select
view_schema, view_name,
(regexp_split_to_array(x[array_upper(x, 1)], ':onConflict'))[1] as x
from target_lists
),
target_entries as(
select
view_schema, view_name,
unnest(regexp_split_to_array(x, 'TARGETENTRY')) as entry
from last_target_list_wo_tail
),
results as(
select
view_schema, view_name,
substring(entry from ':resname (.*?) :') as view_colum_name,
substring(entry from ':resorigtbl (.*?) :') as resorigtbl,
substring(entry from ':resorigcol (.*?) :') as resorigcol
from target_entries
)
select
sch.nspname as table_schema,
tbl.relname as table_name,
col.attname as table_column_name,
res.view_schema,
res.view_name,
res.view_colum_name
from results res
join pg_class tbl on tbl.oid::text = res.resorigtbl
join pg_attribute col on col.attrelid = tbl.oid and col.attnum::text = res.resorigcol
join pg_namespace sch on sch.oid = tbl.relnamespace
where resorigtbl <> '0'
order by view_schema, view_name, view_colum_name;
|]
synonymFromRow :: [Column] -> (Text,Text,Text,Text,Text,Text) -> Maybe Synonym synonymFromRow :: [Column] -> (Text,Text,Text,Text,Text,Text) -> Maybe Synonym
synonymFromRow allCols (s1,t1,c1,s2,t2,c2) = (,) <$> col1 <*> col2 synonymFromRow allCols (s1,t1,c1,s2,t2,c2) = (,) <$> col1 <*> col2
-1
View File
@@ -32,7 +32,6 @@ import qualified Hasql.Decoders as HD
import qualified Data.Aeson as JSON import qualified Data.Aeson as JSON
import PostgREST.Config (pgVersion96)
import PostgREST.RangeQuery (rangeLimit, rangeOffset, allRange) import PostgREST.RangeQuery (rangeLimit, rangeOffset, allRange)
import qualified Data.HashMap.Strict as HM import qualified Data.HashMap.Strict as HM
import Data.Maybe import Data.Maybe
+17 -1
View File
@@ -317,7 +317,23 @@ toMime (CTOther ct) = ct
data PgVersion = PgVersion { data PgVersion = PgVersion {
pgvNum :: Int32 pgvNum :: Int32
, pgvName :: Text , pgvName :: Text
} deriving (Eq, Ord, Show) } deriving (Eq, Show)
instance Ord PgVersion where
(PgVersion v1 _) `compare` (PgVersion v2 _) = v1 `compare` v2
-- | Tells the minimum PostgreSQL version required by this version of PostgREST
minimumPgVersion :: PgVersion
minimumPgVersion = PgVersion 90400 "9.4"
pgVersion95 :: PgVersion
pgVersion95 = PgVersion 90500 "9.5"
pgVersion96 :: PgVersion
pgVersion96 = PgVersion 90600 "9.6"
pgVersion100 :: PgVersion
pgVersion100 = PgVersion 100000 "10"
sourceCTEName :: SqlFragment sourceCTEName :: SqlFragment
sourceCTEName = "pg_source" sourceCTEName = "pg_source"
+1 -2
View File
@@ -6,9 +6,8 @@ import SpecHelper
import qualified Hasql.Pool as P import qualified Hasql.Pool as P
import PostgREST.App (postgrest) import PostgREST.App (postgrest)
import PostgREST.Config (pgVersion95, pgVersion96)
import PostgREST.DbStructure (getDbStructure, getPgVersion) import PostgREST.DbStructure (getDbStructure, getPgVersion)
import PostgREST.Types (DbStructure(..)) import PostgREST.Types (DbStructure(..), pgVersion95, pgVersion96)
import Control.AutoUpdate (defaultUpdateSettings, mkAutoUpdate, updateAction) import Control.AutoUpdate (defaultUpdateSettings, mkAutoUpdate, updateAction)
import Data.Function (id) import Data.Function (id)
import Data.IORef import Data.IORef