Read only proc tx (#844)
This commit is contained in:
@@ -17,6 +17,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
||||
- #777, Empty body is allowed when calling a non-parameterized RPC - @koulakis
|
||||
- #831, Fix proc resource embedding issue with search_path - @steve-chavez
|
||||
- #857, Fix swagger-ui when "server-proxy-uri" is not set - @feynmanliang
|
||||
- #547, Use read-only transaction for stable/immutable RPC - @begriffs
|
||||
|
||||
## [0.4.0.0] - 2017-01-19
|
||||
|
||||
|
||||
+19
-5
@@ -79,15 +79,29 @@ postgrest conf refDbStructure pool getTime =
|
||||
eClaims = jwtClaims jwtSecret (iJWT apiRequest) time
|
||||
authed = containsRole eClaims
|
||||
handleReq = runWithClaims conf eClaims (app dbStructure conf) apiRequest
|
||||
txMode = transactionMode $ iAction apiRequest
|
||||
txMode = transactionMode dbStructure
|
||||
(iTarget apiRequest) (iAction apiRequest)
|
||||
response <- P.use pool $ HT.transaction HT.ReadCommitted txMode handleReq
|
||||
return $ either (pgError authed) identity response
|
||||
respond response
|
||||
|
||||
transactionMode :: Action -> H.Mode
|
||||
transactionMode ActionRead = HT.Read
|
||||
transactionMode ActionInfo = HT.Read
|
||||
transactionMode _ = HT.Write
|
||||
transactionMode :: DbStructure -> Target -> Action -> H.Mode
|
||||
transactionMode structure target action =
|
||||
case action of
|
||||
ActionRead -> HT.Read
|
||||
ActionInfo -> HT.Read
|
||||
ActionInspect -> HT.Read
|
||||
ActionInvoke ->
|
||||
let proc =
|
||||
case target of
|
||||
(TargetProc qi) -> M.lookup (qiName qi) $
|
||||
dbProcs structure
|
||||
_ -> Nothing
|
||||
v = fromMaybe Volatile $ pdVolatility <$> proc in
|
||||
if v == Stable || v == Immutable
|
||||
then HT.Read
|
||||
else HT.Write
|
||||
_ -> HT.Write
|
||||
|
||||
app :: DbStructure -> AppConfig -> ApiRequest -> H.Transaction Response
|
||||
app dbStructure conf apiRequest =
|
||||
|
||||
@@ -100,10 +100,19 @@ decodeSynonyms cols =
|
||||
accessibleProcs :: H.Query Schema (M.HashMap Text ProcDescription)
|
||||
accessibleProcs =
|
||||
H.statement sql (HE.value HE.text)
|
||||
(M.fromList . map addName <$> HD.rowsList (ProcDescription <$> HD.value HD.text
|
||||
<*> (parseArgs <$> HD.value HD.text)
|
||||
<*> (parseRetType <$> HD.value HD.text <*> HD.value HD.text <*>
|
||||
HD.value HD.bool <*> HD.value HD.char))) True
|
||||
(M.fromList . map addName <$>
|
||||
HD.rowsList (
|
||||
ProcDescription <$> HD.value HD.text
|
||||
<*> (parseArgs <$> HD.value HD.text)
|
||||
<*> (parseRetType <$>
|
||||
HD.value HD.text <*>
|
||||
HD.value HD.text <*>
|
||||
HD.value HD.bool <*>
|
||||
HD.value HD.char)
|
||||
<*> (parseVolatility <$>
|
||||
HD.value HD.char)
|
||||
)
|
||||
) True
|
||||
where
|
||||
addName :: ProcDescription -> (Text, ProcDescription)
|
||||
addName pd = (pdName pd, pd)
|
||||
@@ -124,25 +133,32 @@ accessibleProcs =
|
||||
parseRetType schema name isSetOf typ
|
||||
| isSetOf = SetOf pgType
|
||||
| otherwise = Single pgType
|
||||
where
|
||||
where
|
||||
qi = QualifiedIdentifier schema name
|
||||
pgType = case typ of
|
||||
pgType = case typ of
|
||||
'c' -> Composite qi
|
||||
'p' -> Pseudo name
|
||||
_ -> Scalar qi -- 'b'ase, 'd'omain, 'e'num, 'r'ange
|
||||
|
||||
|
||||
parseVolatility :: Char -> ProcVolatility
|
||||
parseVolatility 'i' = Immutable
|
||||
parseVolatility 's' = Stable
|
||||
parseVolatility 'v' = Volatile
|
||||
parseVolatility _ = Volatile -- should not happen, but be pessimistic
|
||||
|
||||
sql = [q|
|
||||
SELECT p.proname as "proc_name",
|
||||
pg_get_function_arguments(p.oid) as "args",
|
||||
tn.nspname as "rettype_schema",
|
||||
coalesce(comp.relname, t.typname) as "rettype_name",
|
||||
p.proretset as "rettype_is_setof",
|
||||
t.typtype as "rettype_typ"
|
||||
t.typtype as "rettype_typ",
|
||||
p.provolatile
|
||||
FROM pg_proc p
|
||||
JOIN pg_namespace pn ON pn.oid = p.pronamespace
|
||||
JOIN pg_type t ON t.oid = p.prorettype
|
||||
JOIN pg_namespace tn ON tn.oid = t.typnamespace
|
||||
LEFT JOIN pg_class comp ON comp.oid = t.typrelid
|
||||
LEFT JOIN pg_class comp ON comp.oid = t.typrelid
|
||||
WHERE pn.nspname = $1|]
|
||||
|
||||
accessibleTables :: H.Query Schema [Table]
|
||||
|
||||
@@ -41,10 +41,14 @@ data PgType = Scalar QualifiedIdentifier | Composite QualifiedIdentifier | Pseud
|
||||
|
||||
data RetType = Single PgType | SetOf PgType deriving (Eq, Show)
|
||||
|
||||
data ProcVolatility = Volatile | Stable | Immutable
|
||||
deriving (Eq, Show)
|
||||
|
||||
data ProcDescription = ProcDescription {
|
||||
pdName :: Text
|
||||
, pdArgs :: [PgArg]
|
||||
, pdReturnType :: RetType
|
||||
, pdVolatility :: ProcVolatility
|
||||
} deriving (Show, Eq)
|
||||
|
||||
type Schema = Text
|
||||
|
||||
Vendored
+1
@@ -316,6 +316,7 @@ $$;
|
||||
|
||||
CREATE FUNCTION sayhello(name text) RETURNS text
|
||||
LANGUAGE sql
|
||||
IMMUTABLE
|
||||
AS $_$
|
||||
SELECT 'Hello, ' || $1;
|
||||
$_$;
|
||||
|
||||
Reference in New Issue
Block a user