diff --git a/CHANGELOG.md b/CHANGELOG.md index 3896bac859..3336ae49c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,6 @@ This project adheres to [Semantic Versioning](http://semver.org/). - #2887, Add Preference `max-affected` to limit affected resources - @taimoorzaeem - #3171, Add an ability to dump config via admin API - @skywriter - - #3061, Apply all function settings as transaction-scoped settings - @taimoorzaeem - #3171, #3046, Log schema cache stats to stderr - @steve-chavez - #3210, Dump schema cache through admin API - @taimoorzaeem - #2676, Performance improvement on bulk json inserts, around 10% increase on requests per second by removing `json_typeof` from write queries - @steve-chavez @@ -23,6 +22,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). + Shows the correct JSON format in the `hints` field - #3340, Log when the LISTEN channel gets a notification - @steve-chavez - #3184, Log full pg version to stderr on connection - @steve-chavez + - #3242. Add config `db-hoisted-tx-settings` to apply only hoisted function settings - @taimoorzaeem ### Fixed diff --git a/docs/references/configuration.rst b/docs/references/configuration.rst index d903b443f6..2740e70537 100644 --- a/docs/references/configuration.rst +++ b/docs/references/configuration.rst @@ -298,6 +298,21 @@ db-extra-search-path Multiple schemas can be added in a comma-separated string, e.g. ``public, extensions``. +.. _db-hoisted-tx-settings: + +db-hoisted-tx-settings +---------------------- + + =============== ================================================================================== + **Type** String + **Default** statement_timeout, plan_filter.statement_cost_limit, default_transaction_isolation + **Reloadable** Y + **Environment** PGRST_DB_HOISTED_TX_SETTINGS + **In-Database** pgrst.db_hoisted_tx_settings + =============== ================================================================================== + + Hoisted settings are allowed to be applied as transaction-scoped function settings. Multiple settings can be added in a comma-separated string, e.g. ``work_mem, statement_timeout``. + .. _db-max-rows: db-max-rows diff --git a/docs/references/transactions.rst b/docs/references/transactions.rst index a6922eb0a7..6bef2b74b6 100644 --- a/docs/references/transactions.rst +++ b/docs/references/transactions.rst @@ -303,7 +303,7 @@ When calling the above function (see :ref:`functions`), the statement timeout wi .. note:: - Currently, only ``statement_timeout`` is applied for functions. + Only the transactions that are hoisted by config :ref:`db-hoisted-tx-settings` will be applied. .. _main_query: diff --git a/src/PostgREST/Config.hs b/src/PostgREST/Config.hs index ef2a7813cc..4a885c7f67 100644 --- a/src/PostgREST/Config.hs +++ b/src/PostgREST/Config.hs @@ -74,6 +74,7 @@ data AppConfig = AppConfig , configDbChannel :: Text , configDbChannelEnabled :: Bool , configDbExtraSearchPath :: [Text] + , configDbHoistedTxSettings :: [Text] , configDbMaxRows :: Maybe Integer , configDbPlanEnabled :: Bool , configDbPoolSize :: Int @@ -146,6 +147,7 @@ toText conf = ,("db-channel", q . configDbChannel) ,("db-channel-enabled", T.toLower . show . configDbChannelEnabled) ,("db-extra-search-path", q . T.intercalate "," . configDbExtraSearchPath) + ,("db-hoisted-tx-settings", q . T.intercalate "," . configDbHoistedTxSettings) ,("db-max-rows", maybe "\"\"" show . configDbMaxRows) ,("db-plan-enabled", T.toLower . show . configDbPlanEnabled) ,("db-pool", show . configDbPoolSize) @@ -241,6 +243,7 @@ parser optPath env dbSettings roleSettings roleIsolationLvl = <*> (fromMaybe "pgrst" <$> optString "db-channel") <*> (fromMaybe True <$> optBool "db-channel-enabled") <*> (maybe ["public"] splitOnCommas <$> optValue "db-extra-search-path") + <*> (maybe defaultHoistedAllowList splitOnCommas <$> optValue "db-hoisted-tx-settings") <*> optWithAlias (optInt "db-max-rows") (optInt "max-rows") <*> (fromMaybe False <$> optBool "db-plan-enabled") @@ -418,6 +421,8 @@ parser optPath env dbSettings roleSettings roleIsolationLvl = splitOnCommas (C.String s) = T.strip <$> T.splitOn "," s splitOnCommas _ = [] + defaultHoistedAllowList = ["statement_timeout","plan_filter.statement_cost_limit","default_transaction_isolation"] + -- | Read the JWT secret from a file if configJwtSecret is actually a -- filepath(has @ as its prefix). To check if the JWT secret is provided is -- in fact a file path, it must be decoded as 'Text' to be processed. diff --git a/src/PostgREST/Config/Database.hs b/src/PostgREST/Config/Database.hs index e7310c990f..4477608429 100644 --- a/src/PostgREST/Config/Database.hs +++ b/src/PostgREST/Config/Database.hs @@ -56,6 +56,7 @@ dbSettingsNames = ,"db_root_spec" ,"db_schemas" ,"db_tx_end" + ,"db_hoisted_tx_settings" ,"jwt_aud" ,"jwt_role_claim_key" ,"jwt_secret" diff --git a/src/PostgREST/Query.hs b/src/PostgREST/Query.hs index 7332f7b417..ab6ddf8cd5 100644 --- a/src/PostgREST/Query.hs +++ b/src/PostgREST/Query.hs @@ -181,7 +181,7 @@ actionQuery (MaybeDb plan@InspectPlan{ipSchema=tSchema}) AppConfig{..} _ pgVer s tableAccess <- SQL.statement [tSchema] (SchemaCache.accessibleTables pgVer configDbPreparedStatements) MaybeDbResult plan . Just <$> ((,,) (HM.filterWithKey (\qi _ -> S.member qi tableAccess) $ SchemaCache.dbTables sCache) - <$> SQL.statement tSchema (SchemaCache.accessibleFuncs pgVer configDbPreparedStatements) + <$> SQL.statement (tSchema, configDbHoistedTxSettings) (SchemaCache.accessibleFuncs pgVer configDbPreparedStatements) <*> SQL.statement tSchema (SchemaCache.schemaDescription configDbPreparedStatements)) OAIgnorePriv -> MaybeDbResult plan . Just <$> ((,,) diff --git a/src/PostgREST/SchemaCache.hs b/src/PostgREST/SchemaCache.hs index 3811a7b8e5..b6dca5ba14 100644 --- a/src/PostgREST/SchemaCache.hs +++ b/src/PostgREST/SchemaCache.hs @@ -150,7 +150,7 @@ querySchemaCache AppConfig{..} = do tabs <- SQL.statement schemas $ allTables pgVer prepared keyDeps <- SQL.statement (schemas, configDbExtraSearchPath) $ allViewsKeyDependencies prepared m2oRels <- SQL.statement mempty $ allM2OandO2ORels pgVer prepared - funcs <- SQL.statement schemas $ allFunctions pgVer prepared + funcs <- SQL.statement (schemas, configDbHoistedTxSettings) $ allFunctions pgVer prepared cRels <- SQL.statement mempty $ allComputedRels prepared reps <- SQL.statement schemas $ dataRepresentations prepared mHdlers <- SQL.statement schemas $ mediaHandlers pgVer prepared @@ -363,13 +363,13 @@ dataRepresentations = SQL.Statement sql (arrayParam HE.text) decodeRepresentatio OR (dst_t.typtype = 'd' AND c.castsource IN ('json'::regtype::oid , 'text'::regtype::oid))) |] -allFunctions :: PgVersion -> Bool -> SQL.Statement [Schema] RoutineMap -allFunctions pgVer = SQL.Statement sql (arrayParam HE.text) decodeFuncs +allFunctions :: PgVersion -> Bool -> SQL.Statement ([Schema], [Text]) RoutineMap +allFunctions pgVer = SQL.Statement sql (contrazip2 (arrayParam HE.text) (arrayParam HE.text)) decodeFuncs where sql = funcsSqlQuery pgVer <> " AND pn.nspname = ANY($1)" -accessibleFuncs :: PgVersion -> Bool -> SQL.Statement Schema RoutineMap -accessibleFuncs pgVer = SQL.Statement sql (param HE.text) decodeFuncs +accessibleFuncs :: PgVersion -> Bool -> SQL.Statement (Schema, [Text]) RoutineMap +accessibleFuncs pgVer = SQL.Statement sql (contrazip2 (param HE.text) (arrayParam HE.text)) decodeFuncs where sql = funcsSqlQuery pgVer <> " AND pn.nspname = $1 AND has_function_privilege(p.oid, 'execute')" @@ -451,7 +451,7 @@ funcsSqlQuery pgVer = [q| JOIN pg_namespace tn ON tn.oid = t.typnamespace 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) iso_config ON iso_config LIKE 'default_transaction_isolation%' LEFT JOIN LATERAL ( SELECT array_agg(row( @@ -459,7 +459,7 @@ funcsSqlQuery pgVer = [q| substr(setting, strpos(setting, '=') + 1) )) as kvs FROM unnest(proconfig) setting - WHERE setting not LIKE 'default_transaction_isolation%' + WHERE setting ~ ANY($2) ) func_settings ON TRUE WHERE t.oid <> 'trigger'::regtype AND COALESCE(a.callable, true) |] <> (if pgVer >= pgVersion110 then "AND prokind = 'f'" else "AND NOT (proisagg OR proiswindow)") diff --git a/test/io/__snapshots__/test_cli/test_schema_cache_snapshot[dbRoutines].yaml b/test/io/__snapshots__/test_cli/test_schema_cache_snapshot[dbRoutines].yaml index dc538ba52e..8c46a3393e 100644 --- a/test/io/__snapshots__/test_cli/test_schema_cache_snapshot[dbRoutines].yaml +++ b/test/io/__snapshots__/test_cli/test_schema_cache_snapshot[dbRoutines].yaml @@ -59,31 +59,32 @@ pdSchema: public pdVolatility: Volatile -- - qiName: multiple_func_settings_test +- - qiName: rpc_with_one_hoisted qiSchema: public - - pdDescription: null pdFuncSettings: - - - work_mem - - '5000' - - statement_timeout - - 10s + - 7s pdHasVariadic: false - pdName: multiple_func_settings_test + pdName: rpc_with_one_hoisted pdParams: [] pdReturnType: contents: contents: - qiName: record - qiSchema: pg_catalog - tag: Scalar - tag: SetOf + - qiName: items + qiSchema: public + - false + tag: Composite + tag: Single pdSchema: public pdVolatility: Volatile - - qiName: serializable_isolation_level qiSchema: public - - pdDescription: null - pdFuncSettings: [] + pdFuncSettings: + - - default_transaction_isolation + - serializable pdHasVariadic: false pdName: serializable_isolation_level pdParams: [] @@ -170,6 +171,26 @@ pdSchema: public pdVolatility: Volatile +- - qiName: rpc_with_two_hoisted + qiSchema: public + - - pdDescription: null + pdFuncSettings: + - - statement_timeout + - 10s + pdHasVariadic: false + pdName: rpc_with_two_hoisted + pdParams: [] + pdReturnType: + contents: + contents: + - qiName: items + qiSchema: public + - false + tag: Composite + tag: Single + pdSchema: public + pdVolatility: Volatile + - - qiName: set_statement_timeout qiSchema: public - - pdDescription: null @@ -219,25 +240,6 @@ pdSchema: public pdVolatility: Volatile -- - qiName: work_mem_test - qiSchema: public - - - pdDescription: null - pdFuncSettings: - - - work_mem - - 6000kB - pdHasVariadic: false - pdName: work_mem_test - pdParams: [] - pdReturnType: - contents: - contents: - qiName: text - qiSchema: pg_catalog - tag: Scalar - tag: Single - pdSchema: public - pdVolatility: Volatile - - - qiName: invalid_role_claim_key_reload qiSchema: public - - pdDescription: null @@ -348,7 +350,9 @@ - - qiName: repeatable_read_isolation_level qiSchema: public - - pdDescription: null - pdFuncSettings: [] + pdFuncSettings: + - - default_transaction_isolation + - REPEATABLE READ pdHasVariadic: false pdName: repeatable_read_isolation_level pdParams: [] @@ -454,6 +458,24 @@ pdSchema: public pdVolatility: Volatile +- - qiName: rpc_work_mem + qiSchema: public + - - pdDescription: null + pdFuncSettings: [] + pdHasVariadic: false + pdName: rpc_work_mem + pdParams: [] + pdReturnType: + contents: + contents: + - qiName: items + qiSchema: public + - false + tag: Composite + tag: Single + pdSchema: public + pdVolatility: Volatile + - - qiName: four_sec_timeout qiSchema: public - - pdDescription: null diff --git a/test/io/configs/expected/aliases.config b/test/io/configs/expected/aliases.config index bf2df05a11..00d9414e05 100644 --- a/test/io/configs/expected/aliases.config +++ b/test/io/configs/expected/aliases.config @@ -3,6 +3,7 @@ db-anon-role = "" db-channel = "pgrst" db-channel-enabled = true db-extra-search-path = "public" +db-hoisted-tx-settings = "statement_timeout,plan_filter.statement_cost_limit,default_transaction_isolation" db-max-rows = 1000 db-plan-enabled = false db-pool = 10 diff --git a/test/io/configs/expected/boolean-numeric.config b/test/io/configs/expected/boolean-numeric.config index 1359f09fef..5c025e0c16 100644 --- a/test/io/configs/expected/boolean-numeric.config +++ b/test/io/configs/expected/boolean-numeric.config @@ -3,6 +3,7 @@ db-anon-role = "" db-channel = "pgrst" db-channel-enabled = true db-extra-search-path = "public" +db-hoisted-tx-settings = "statement_timeout,plan_filter.statement_cost_limit,default_transaction_isolation" db-max-rows = "" db-plan-enabled = false db-pool = 10 diff --git a/test/io/configs/expected/boolean-string.config b/test/io/configs/expected/boolean-string.config index 1359f09fef..5c025e0c16 100644 --- a/test/io/configs/expected/boolean-string.config +++ b/test/io/configs/expected/boolean-string.config @@ -3,6 +3,7 @@ db-anon-role = "" db-channel = "pgrst" db-channel-enabled = true db-extra-search-path = "public" +db-hoisted-tx-settings = "statement_timeout,plan_filter.statement_cost_limit,default_transaction_isolation" db-max-rows = "" db-plan-enabled = false db-pool = 10 diff --git a/test/io/configs/expected/defaults.config b/test/io/configs/expected/defaults.config index aefd98aa0d..1d0c095d61 100644 --- a/test/io/configs/expected/defaults.config +++ b/test/io/configs/expected/defaults.config @@ -3,6 +3,7 @@ db-anon-role = "" db-channel = "pgrst" db-channel-enabled = true db-extra-search-path = "public" +db-hoisted-tx-settings = "statement_timeout,plan_filter.statement_cost_limit,default_transaction_isolation" db-max-rows = "" db-plan-enabled = false db-pool = 10 diff --git a/test/io/configs/expected/no-defaults-with-db-other-authenticator.config b/test/io/configs/expected/no-defaults-with-db-other-authenticator.config index ffa9fd5280..3717e99e57 100644 --- a/test/io/configs/expected/no-defaults-with-db-other-authenticator.config +++ b/test/io/configs/expected/no-defaults-with-db-other-authenticator.config @@ -3,6 +3,7 @@ db-anon-role = "pre_config_role" db-channel = "postgrest" db-channel-enabled = false db-extra-search-path = "public,extensions,other" +db-hoisted-tx-settings = "maintenance_work_mem" db-max-rows = 100 db-plan-enabled = true db-pool = 1 diff --git a/test/io/configs/expected/no-defaults-with-db.config b/test/io/configs/expected/no-defaults-with-db.config index a78347593c..5f78327baf 100644 --- a/test/io/configs/expected/no-defaults-with-db.config +++ b/test/io/configs/expected/no-defaults-with-db.config @@ -3,6 +3,7 @@ db-anon-role = "anonymous" db-channel = "postgrest" db-channel-enabled = false db-extra-search-path = "public,extensions,private" +db-hoisted-tx-settings = "autovacuum_work_mem" db-max-rows = 500 db-plan-enabled = false db-pool = 1 diff --git a/test/io/configs/expected/no-defaults.config b/test/io/configs/expected/no-defaults.config index 2a45b21df0..57f6b2dc0f 100644 --- a/test/io/configs/expected/no-defaults.config +++ b/test/io/configs/expected/no-defaults.config @@ -3,6 +3,7 @@ db-anon-role = "root" db-channel = "postgrest" db-channel-enabled = false db-extra-search-path = "public,test" +db-hoisted-tx-settings = "work_mem" db-max-rows = 1000 db-plan-enabled = true db-pool = 1 diff --git a/test/io/configs/expected/types.config b/test/io/configs/expected/types.config index e6d0328b65..b363c94bb4 100644 --- a/test/io/configs/expected/types.config +++ b/test/io/configs/expected/types.config @@ -3,6 +3,7 @@ db-anon-role = "" db-channel = "pgrst" db-channel-enabled = true db-extra-search-path = "public" +db-hoisted-tx-settings = "statement_timeout,plan_filter.statement_cost_limit,default_transaction_isolation" db-max-rows = "" db-plan-enabled = false db-pool = 10 diff --git a/test/io/configs/no-defaults-env.yaml b/test/io/configs/no-defaults-env.yaml index 4f03111a28..915497b18c 100644 --- a/test/io/configs/no-defaults-env.yaml +++ b/test/io/configs/no-defaults-env.yaml @@ -5,6 +5,7 @@ PGRST_DB_ANON_ROLE: root PGRST_DB_CHANNEL: postgrest PGRST_DB_CHANNEL_ENABLED: false PGRST_DB_EXTRA_SEARCH_PATH: public, test +PGRST_DB_HOISTED_TX_SETTINGS: work_mem PGRST_DB_MAX_ROWS: 1000 PGRST_DB_PLAN_ENABLED: true PGRST_DB_POOL: 1 diff --git a/test/io/configs/no-defaults.config b/test/io/configs/no-defaults.config index d9944c352a..1f54505a32 100644 --- a/test/io/configs/no-defaults.config +++ b/test/io/configs/no-defaults.config @@ -3,6 +3,7 @@ db-anon-role = "root" db-channel = "postgrest" db-channel-enabled = false db-extra-search-path = "public, test" +db-hoisted-tx-settings = "work_mem" db-max-rows = 1000 db-plan-enabled = true db-pool = 1 diff --git a/test/io/db_config.sql b/test/io/db_config.sql index 1703fdf9eb..630e3e5cd8 100644 --- a/test/io/db_config.sql +++ b/test/io/db_config.sql @@ -23,6 +23,7 @@ ALTER ROLE db_config_authenticator SET pgrst.openapi_server_proxy_uri = 'https:/ ALTER ROLE db_config_authenticator SET pgrst.server_cors_allowed_origins = 'http://origin.com'; ALTER ROLE db_config_authenticator SET pgrst.server_timing_enabled = 'false'; ALTER ROLE db_config_authenticator SET pgrst.server_trace_header = 'CF-Ray'; +ALTER ROLE db_config_authenticator SET pgrst.db_hoisted_tx_settings = 'autovacuum_work_mem'; -- override with database specific setting ALTER ROLE db_config_authenticator IN DATABASE :DBNAME SET pgrst.db_extra_search_path = 'public, extensions, private'; @@ -72,6 +73,7 @@ ALTER ROLE other_authenticator SET pgrst.openapi_server_proxy_uri = 'https://oth ALTER ROLE other_authenticator SET pgrst.server_cors_allowed_origins = 'http://otherorigin.com'; ALTER ROLE other_authenticator SET pgrst.server_timing_enabled = 'true'; ALTER ROLE other_authenticator SET pgrst.server_trace_header = 'traceparent'; +ALTER ROLE other_authenticator SET pgrst.db_hoisted_tx_settings = 'maintenance_work_mem'; create schema postgrest; grant usage on schema postgrest to db_config_authenticator; diff --git a/test/io/fixtures.sql b/test/io/fixtures.sql index 4b323be200..53446adee7 100644 --- a/test/io/fixtures.sql +++ b/test/io/fixtures.sql @@ -1,4 +1,3 @@ --- \ir big_schema.sql big schema test currently skipped, see test_io.py \ir db_config.sql set check_function_bodies = false; -- to allow conditionals based on the pg version @@ -203,13 +202,27 @@ create function get_postgres_version() returns int as $$ select current_setting('server_version_num')::int; $$ language sql; -create or replace function work_mem_test() returns text as $$ - select current_setting('work_mem',false); -$$ language sql set work_mem = '6000kB'; +create or replace function rpc_work_mem() returns items as $$ + select 1 +$$ language sql +set work_mem = '6000'; + +create or replace function rpc_with_one_hoisted() returns items as $$ + select 1 +$$ language sql +set work_mem = '3000' +set statement_timeout = '7s'; -create or replace function multiple_func_settings_test() returns setof record as $$ - select current_setting('work_mem',false) as work_mem, - current_setting('statement_timeout',false) as statement_timeout; +create or replace function rpc_with_two_hoisted() returns items as $$ + select 1 $$ language sql set work_mem = '5000' set statement_timeout = '10s'; + +create function get_work_mem(items) returns text as $$ + select current_setting('work_mem', true) as work_mem +$$ language sql; + +create function get_statement_timeout(items) returns text as $$ + select current_setting('statement_timeout', true) as statement_timeout +$$ language sql; diff --git a/test/io/test_io.py b/test/io/test_io.py index 74d890def3..d893440faa 100644 --- a/test/io/test_io.py +++ b/test/io/test_io.py @@ -1492,19 +1492,65 @@ def test_function_setting_statement_timeout_passes(defaultenv): def test_function_setting_work_mem(defaultenv): "check function setting work_mem is applied" - with run(env=defaultenv) as postgrest: - response = postgrest.session.post("/rpc/work_mem_test") + env = { + **defaultenv, + "PGRST_DB_HOISTED_TX_SETTINGS": "work_mem", + } + + with run(env=env) as postgrest: + response = postgrest.session.get("/rpc/rpc_work_mem?select=get_work_mem") - assert response.text == '"6000kB"' + assert response.text == '{"get_work_mem":"6000kB"}' def test_multiple_func_settings(defaultenv): "check multiple function settings are applied" - with run(env=defaultenv) as postgrest: - response = postgrest.session.post("/rpc/multiple_func_settings_test") + env = { + **defaultenv, + "PGRST_DB_HOISTED_TX_SETTINGS": "work_mem,statement_timeout", + } + + with run(env=env) as postgrest: + response = postgrest.session.get( + "/rpc/rpc_with_two_hoisted?select=get_work_mem,get_statement_timeout" + ) + + assert ( + response.text == '{"get_work_mem":"5000kB","get_statement_timeout":"10s"}' + ) + + +def test_first_hoisted_setting_is_applied(defaultenv): + "test that work_mem is applied and statement_timeout is not applied" + + env = { + **defaultenv, + "PGRST_DB_HOISTED_TX_SETTINGS": "work_mem", # only work_mem is hoisted + } + + with run(env=env) as postgrest: + response = postgrest.session.get( + "/rpc/rpc_with_one_hoisted?select=get_work_mem,get_statement_timeout" + ) + + assert response.text == '{"get_work_mem":"3000kB","get_statement_timeout":"2s"}' + + +def test_second_hoisted_setting_is_applied(defaultenv): + "test that statement_timeout is applied and work_mem is not applied" + + env = { + **defaultenv, + "PGRST_DB_HOISTED_TX_SETTINGS": "statement_timeout", + } + + with run(env=env) as postgrest: + response = postgrest.session.get( + "/rpc/rpc_with_one_hoisted?select=get_work_mem,get_statement_timeout" + ) - assert response.text == '[{"work_mem":"5000kB","statement_timeout":"10s"}]' + assert response.text == '{"get_work_mem":"4MB","get_statement_timeout":"7s"}' def test_admin_metrics(defaultenv): diff --git a/test/spec/SpecHelper.hs b/test/spec/SpecHelper.hs index 4e9b4fcde7..e4e64b41b5 100644 --- a/test/spec/SpecHelper.hs +++ b/test/spec/SpecHelper.hs @@ -116,6 +116,7 @@ baseCfg = let secret = Just $ encodeUtf8 "reallyreallyreallyreallyverysafe" in , configDbChannel = mempty , configDbChannelEnabled = True , configDbExtraSearchPath = [] + , configDbHoistedTxSettings = ["default_transaction_isolation","plan_filter.statement_cost_limit","statement_timeout"] , configDbMaxRows = Nothing , configDbPlanEnabled = False , configDbPoolSize = 10