-
-
Notifications
You must be signed in to change notification settings - Fork 1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: apply all function settings as transaction-scoped settings #3142
Conversation
queryFuncSettings :: PgVersion -> Bool -> Session FunctionSettings
queryFuncSettings pgVer prepared =
let transaction = if prepared then SQL.transaction else SQL.unpreparedTransaction in
transaction SQL.ReadCommitted SQL.Read $ SQL.statement mempty $ SQL.Statement sql HE.noParams (processRows <$> rows) prepared
where
sql = [q|
WITH
func_setting AS (
SELECT current_user AS rolname, unnest(p.proconfig) as setting
FROM pg_proc p
),
kv_settings AS (
SELECT
rolname,
substr(setting, 1, strpos(setting, '=') - 1) AS key,
lower(substr(setting, strpos(setting, '=') + 1)) AS value
FROM func_setting
),
SELECT
kv.rolname,
array_agg(row(kv.key, kv.value)) AS func_setting
FROM kv_settings kv
JOIN pg_settings ps on ps.name = kv.key |] <>
(if pgVer >= pgVersion150
then "and (ps.context = 'user' or has_parameter_privilege(current_user::regrole::oid, ps.name, 'set')) "
else "and ps.context = 'user' ") <> [q|
GROUP BY kv.rolname; @steve-chavez With the function settings defined as: type FunctionSettings = (HM.HashMap ByteString (HM.HashMap ByteString ByteString)) The first |
@taimoorzaeem We don't need a role here. Since the settings are defined in the function, we only need the settings from |
18ba174
to
d2fb67f
Compare
@steve-chavez The type of FuncSettings is: type FuncSettings = [(ByteString,ByteString,ByteString)] I think a hashmap would be better performance-wise but I'm not sure. |
@taimoorzaeem How about having the function settings as part of: postgrest/src/PostgREST/SchemaCache/Routine.hs Lines 52 to 62 in d2fb67f
Then you wouldn't need to worry about search because the Function is already searched on Edit: Btw don't worry about the tests failures on older pg versions. We can figure that out later. |
a138f39
to
f354c88
Compare
src/PostgREST/SchemaCache.hs
Outdated
-- the proconfig is returned as text[], which returns something like | ||
-- e.g "\NUL\NUL\DB4statement_timeout=1s", this is solved by using | ||
-- selecting first element | ||
(p.proconfig)[1] AS func_setting |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@taimoorzaeem This won't work if the function has two settings like:
create or replace function four_sec_timeout() returns void as $$
select pg_sleep(3);
$$ language sql
set statement_timeout = '4s'
set log_min_duration_sample = '5s';
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just tested this and the query on this part should be like:
coalesce(func_settings.kvs, '{}') as kvs
And below..
@@ -442,7 +452,6 @@ funcsSqlQuery pgVer = [q| | |||
LEFT JOIN pg_class comp ON comp.oid = t.typrelid | |||
LEFT JOIN pg_description as d ON d.objoid = p.oid | |||
LEFT JOIN LATERAL unnest(proconfig) iso_config ON iso_config like 'default_transaction_isolation%' | |||
LEFT JOIN LATERAL unnest(proconfig) timeout_config ON timeout_config like 'statement_timeout%' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use this query here:
LEFT JOIN LATERAL (
SELECT
array_agg(row(
substr(setting, 1, strpos(setting, '=') - 1),
lower(substr(setting, strpos(setting, '=') + 1))
)) as kvs
FROM unnest(proconfig) setting
WHERE setting not like 'default_transaction_isolation%'
) func_settings ON TRUE
This will output the settings like:
-[ RECORD 14 ]--------------+--------------------------------------------------------------
proc_schema | public
proc_name | four_sec_timeout
kvs | {"(statement_timeout,4s)","(log_min_duration_sample,5s)"}
src/PostgREST/SchemaCache.hs
Outdated
parseFuncSetting :: Text -> FuncSetting | ||
parseFuncSetting txt = toTuple $ T.splitOn "=" txt | ||
where | ||
toTuple [x,y] = (x,y) | ||
toTuple _ = ("error","parsing") | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The decoding would then need to use compositeArrayColumn
, like done here:
postgrest/src/PostgREST/Config/Database.hs
Lines 181 to 182 in 4958472
rows :: HD.Result [(Text, Maybe Text, [(Text, Text)])] | |
rows = HD.rowList $ (,,) <$> column HD.text <*> nullableColumn HD.text <*> compositeArrayColumn ((,) <$> compositeField HD.text <*> compositeField HD.text) |
This won't need text splitting on the Haskell code.
src/PostgREST/SchemaCache/Routine.hs
Outdated
@@ -49,6 +50,8 @@ data FuncVolatility | |||
| Immutable | |||
deriving (Eq, Show, Ord, Generic, JSON.ToJSON) | |||
|
|||
type FuncSetting = (Text,Text) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With the above changes then this type should be:
type FuncSetting = (Text,Text) | |
type FuncSettings = [(Text,Text)] |
src/PostgREST/SchemaCache/Routine.hs
Outdated
@@ -58,12 +61,12 @@ data Routine = Function | |||
, pdVolatility :: FuncVolatility | |||
, pdHasVariadic :: Bool | |||
, pdIsoLvl :: Maybe SQL.IsolationLevel | |||
, pdTimeout :: Maybe Text | |||
, pdFuncSetting :: Maybe FuncSetting |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
, pdFuncSetting :: Maybe FuncSetting | |
, pdFuncSettings :: FuncSettings |
test/io/fixtures.sql
Outdated
|
||
GRANT SET ON PARAMETER log_min_duration_sample TO postgrest_test_anonymous; | ||
|
||
create or replace function log_min_duration_test() returns text as $$ | ||
select current_setting('log_min_duration_sample',false); | ||
$$ language sql set log_min_duration_sample = '5s'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this causes an error on older pg versions, maybe you can use work_mem instead.
IIRC it won't require a GRANT.
GRANT SET ON PARAMETER log_min_duration_sample TO postgrest_test_anonymous; | |
create or replace function log_min_duration_test() returns text as $$ | |
select current_setting('log_min_duration_sample',false); | |
$$ language sql set log_min_duration_sample = '5s'; | |
create or replace function work_mem_test() returns text as $$ | |
select current_setting('work_mem',false); | |
$$ language sql set work_mem = '6000'; |
f354c88
to
b08c2ad
Compare
Hm, the Build Linux static (Nix) CI job is failing with |
I pushed one of the commits out of #3211 to main. Hopefully this fixes it for the moment. I am working on more things that should improve this, though. |
Fixes #3061.