Prepared statement for set_config

This commit is contained in:
steve-chavez
2020-12-07 20:09:18 -05:00
committed by Steve Chavez
parent 7069bb3c01
commit 11d62a8010
5 changed files with 36 additions and 26 deletions
+1 -1
View File
@@ -16,7 +16,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- #504, Add `log-level` config option. The admitted levels are: crit, error, warn and info - @steve-chavez - #504, Add `log-level` config option. The admitted levels are: crit, error, warn and info - @steve-chavez
- #1607, Enable embedding through multiple views recursively - @wolfgangwalther - #1607, Enable embedding through multiple views recursively - @wolfgangwalther
- #1598, Allow rollback of the transaction with Prefer tx=rollback - @wolfgangwalther - #1598, Allow rollback of the transaction with Prefer tx=rollback - @wolfgangwalther
- #1633, Enable prepared statements for filters. When behind a connection pooler, you can disable preparing with `db-prepared-statements=false` - @steve-chavez - #1633, #1600, Enable prepared statements for filters. When behind a connection pooler, you can disable preparing with `db-prepared-statements=false` - @steve-chavez
### Fixed ### Fixed
+18 -11
View File
@@ -8,16 +8,21 @@ Description : Sets CORS policy. Also the PostgreSQL GUCs, role, search_path and
module PostgREST.Middleware where module PostgREST.Middleware where
import qualified Data.Aeson as JSON import qualified Hasql.Decoders as HD
import qualified Data.ByteString.Char8 as BS import qualified Hasql.DynamicStatements.Statement as H
import qualified Data.CaseInsensitive as CI import PostgREST.Private.Common
import Data.Function (id)
import qualified Data.HashMap.Strict as M import qualified Data.Aeson as JSON
import Data.List (lookup) import qualified Data.ByteString.Char8 as BS
import Data.Scientific (FPFormat (..), import qualified Data.CaseInsensitive as CI
formatScientific, isInteger) import Data.Function (id)
import qualified Data.Text as T import qualified Data.HashMap.Strict as M
import qualified Hasql.Transaction as H import Data.List (lookup)
import Data.Scientific (FPFormat (..),
formatScientific,
isInteger)
import qualified Data.Text as T
import qualified Hasql.Transaction as H
import Network.HTTP.Types.Status (Status, status400, import Network.HTTP.Types.Status (Status, status400,
status500, statusCode) status500, statusCode)
import Network.Wai.Logger (showSockAddr) import Network.Wai.Logger (showSockAddr)
@@ -43,7 +48,9 @@ runPgLocals :: AppConfig -> M.HashMap Text JSON.Value ->
(ApiRequest -> H.Transaction Response) -> (ApiRequest -> H.Transaction Response) ->
ApiRequest -> H.Transaction Response ApiRequest -> H.Transaction Response
runPgLocals conf claims app req = do runPgLocals conf claims app req = do
H.sql . toS $ "select " <> T.intercalate ", " (searchPathSql : roleSql ++ claimsSql ++ [methodSql, pathSql] ++ headersSql ++ cookiesSql ++ appSettingsSql) H.statement mempty $ H.dynamicallyParameterized
("select " <> intercalateSnippet ", " (searchPathSql : roleSql ++ claimsSql ++ [methodSql, pathSql] ++ headersSql ++ cookiesSql ++ appSettingsSql))
HD.noResult (configDbPreparedStatements conf)
traverse_ H.sql preReqSql traverse_ H.sql preReqSql
app req app req
where where
+12 -2
View File
@@ -5,10 +5,13 @@ Description : Common helper functions.
module PostgREST.Private.Common where module PostgREST.Private.Common where
import Data.Maybe import Data.Maybe
import qualified Hasql.Decoders as HD import qualified Hasql.Decoders as HD
import qualified Hasql.Encoders as HE import qualified Hasql.DynamicStatements.Snippet as H
import qualified Hasql.Encoders as HE
import Protolude import Protolude
import Data.Foldable (foldr1)
column :: HD.Value a -> HD.Row a column :: HD.Value a -> HD.Row a
column = HD.column . HD.nonNullable column = HD.column . HD.nonNullable
@@ -23,3 +26,10 @@ param = HE.param . HE.nonNullable
arrayParam :: HE.Value a -> HE.Params [a] arrayParam :: HE.Value a -> HE.Params [a]
arrayParam = param . HE.array . HE.dimension foldl' . HE.element . HE.nonNullable arrayParam = param . HE.array . HE.dimension foldl' . HE.element . HE.nonNullable
emptySnippetOnFalse :: H.Snippet -> Bool -> H.Snippet
emptySnippetOnFalse val cond = if cond then mempty else val
intercalateSnippet :: ByteString -> [H.Snippet] -> H.Snippet
intercalateSnippet _ [] = mempty
intercalateSnippet frag snippets = foldr1 (\a b -> a <> H.sql frag <> b) snippets
+2 -10
View File
@@ -30,9 +30,8 @@ import Protolude hiding (cast,
import Protolude.Conv (toS) import Protolude.Conv (toS)
import Text.InterpolatedString.Perl6 (qc) import Text.InterpolatedString.Perl6 (qc)
import qualified Hasql.Encoders as HE import qualified Hasql.Encoders as HE
import PostgREST.Private.Common
import Data.Foldable (foldr1)
noLocationF :: SqlFragment noLocationF :: SqlFragment
noLocationF = "array[]::text[]" noLocationF = "array[]::text[]"
@@ -250,10 +249,3 @@ unknownEncoder = H.encoderAndParam (HE.nonNullable HE.unknown)
unknownLiteral :: Text -> H.Snippet unknownLiteral :: Text -> H.Snippet
unknownLiteral = unknownEncoder . encodeUtf8 unknownLiteral = unknownEncoder . encodeUtf8
emptySnippetOnFalse :: H.Snippet -> Bool -> H.Snippet
emptySnippetOnFalse val cond = if cond then mempty else val
intercalateSnippet :: SqlFragment -> [H.Snippet] -> H.Snippet
intercalateSnippet _ [] = mempty
intercalateSnippet frag snippets = foldr1 (\a b -> a <> H.sql frag <> b) snippets
+3 -2
View File
@@ -26,6 +26,7 @@ import qualified Hasql.DynamicStatements.Snippet as H
import Data.Tree (Tree (..)) import Data.Tree (Tree (..))
import Data.Maybe import Data.Maybe
import PostgREST.Private.Common
import PostgREST.Private.QueryFragment import PostgREST.Private.QueryFragment
import PostgREST.Types import PostgREST.Types
import Protolude hiding (cast, intercalate, import Protolude hiding (cast, intercalate,
@@ -173,6 +174,6 @@ limitedQuery :: H.Snippet -> Maybe Integer -> H.Snippet
limitedQuery query maxRows = query <> H.sql (maybe mempty (\x -> " LIMIT " <> BS.pack (show x)) maxRows) limitedQuery query maxRows = query <> H.sql (maybe mempty (\x -> " LIMIT " <> BS.pack (show x)) maxRows)
-- | Do a pg set_config(setting, value, true) call. This is equivalent to a SET LOCAL. -- | Do a pg set_config(setting, value, true) call. This is equivalent to a SET LOCAL.
setConfigLocal :: Text -> (Text, Text) -> Text setConfigLocal :: Text -> (Text, Text) -> H.Snippet
setConfigLocal prefix (k, v) = setConfigLocal prefix (k, v) =
"set_config(" <> decodeUtf8 (pgFmtLit (prefix <> k)) <> ", " <> decodeUtf8 (pgFmtLit v) <> ", true)" "set_config(" <> unknownLiteral (prefix <> k) <> ", " <> unknownLiteral v <> ", true)"