diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f44bbd3c..819d77642 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,10 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## Unreleased +## Fixed + +- Fix `db-pre-config` function failing when function names are pg reserved words by @taimoorzaeem #4380 + ## [14.0] - 2025-10-24 ### Added diff --git a/src/PostgREST/AppState.hs b/src/PostgREST/AppState.hs index 9a65871cc..a2ac5862a 100644 --- a/src/PostgREST/AppState.hs +++ b/src/PostgREST/AppState.hs @@ -69,7 +69,7 @@ import PostgREST.Config.PgVersion (PgVersion (..), import PostgREST.SchemaCache (SchemaCache (..), querySchemaCache, showSummary) -import PostgREST.SchemaCache.Identifiers (dumpQi) +import PostgREST.SchemaCache.Identifiers (quoteQi) import PostgREST.Unix (createAndBindDomainSocket) import Data.Streaming.Network (bindPortTCP, bindRandomPortTCP) @@ -441,7 +441,7 @@ readInDbConfig startingUp appState@AppState{stateObserver=observer} = do pgVer <- getPgVersion appState dbSettings <- if configDbConfig conf then do - qDbSettings <- usePool appState (queryDbSettings (dumpQi <$> configDbPreConfig conf) (configDbPreparedStatements conf)) + qDbSettings <- usePool appState (queryDbSettings (quoteQi <$> configDbPreConfig conf) (configDbPreparedStatements conf)) case qDbSettings of Left e -> do observer $ ConfigReadErrorObs e diff --git a/src/PostgREST/SchemaCache/Identifiers.hs b/src/PostgREST/SchemaCache/Identifiers.hs index a73d970cd..746d6cd5e 100644 --- a/src/PostgREST/SchemaCache/Identifiers.hs +++ b/src/PostgREST/SchemaCache/Identifiers.hs @@ -10,6 +10,7 @@ module PostgREST.SchemaCache.Identifiers , dumpQi , escapeIdent , isAnyElement + , quoteQi , toQi , trimNullChars ) where @@ -41,6 +42,10 @@ dumpQi :: QualifiedIdentifier -> Text dumpQi (QualifiedIdentifier s i) = (if T.null s then mempty else s <> ".") <> i +quoteQi :: QualifiedIdentifier -> Text +quoteQi (QualifiedIdentifier s i) = + (if T.null s then mempty else escapeIdent s <> ".") <> escapeIdent i + -- TODO: Handle a case where the QI comes like this: "my.fav.schema"."my.identifier" -- Right now it only handles the schema.identifier case toQi :: Text -> QualifiedIdentifier 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 ff0102673..b3be27232 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 @@ -461,6 +461,23 @@ pdSchema: public pdVolatility: Volatile +- - qiName: 'true' + qiSchema: public + - - pdDescription: null + pdFuncSettings: [] + pdHasVariadic: false + pdName: 'true' + pdParams: [] + pdReturnType: + contents: + contents: + qiName: bool + qiSchema: pg_catalog + tag: Scalar + tag: Single + pdSchema: public + pdVolatility: Volatile + - - qiName: create_function qiSchema: public - - pdDescription: null diff --git a/test/io/fixtures.sql b/test/io/fixtures.sql index 0aeeb1a3c..f40fd4554 100644 --- a/test/io/fixtures.sql +++ b/test/io/fixtures.sql @@ -256,3 +256,7 @@ select * from projects; create or replace view infinite_recursion as select * from infinite_recursion; + +create or replace function "true"() returns boolean as $_$ + select true; +$_$ language sql; diff --git a/test/io/test_io.py b/test/io/test_io.py index 441eac4d7..a02d29948 100644 --- a/test/io/test_io.py +++ b/test/io/test_io.py @@ -2046,3 +2046,29 @@ def test_log_listener_connection_errors(defaultenv): in line for line in output ) + + +def test_db_pre_config_with_pg_reserved_words(defaultenv): + "The db-pre-config should not fail unexpectedly when function name is a postgres reserved word" + + env = { + **defaultenv, + "PGRST_DB_PRE_CONFIG": "true", # call true function + } + + with run(env=env) as postgrest: + response = postgrest.session.post("/rpc/true") + assert response.status_code == 200 + + env = { + **defaultenv, + "PGRST_DB_PRE_CONFIG": "select", # no "select" function in our fixtures, fail gracefully at startup + } + + with run(env=env, no_startup_stdout=False, wait_for_readiness=False) as postgrest: + output = postgrest.read_stdout(nlines=8) + assert any( + 'Failed to query database settings for the config parameters.{"code":"42883","details":null,"hint":"No function matches the given name and argument types. You might need to add explicit type casts.","message":"function select() does not exist"}' + in line + for line in output + )