fix: geojson invalid query on unavailable PostGIS
Closes https://github.com/PostgREST/postgrest/issues/4245. It adds a query on schema cache construction, but doesn't add a new attribute to the SchemaCache type. We only need the information to be passed to the `initialMediaHandlers` function to build the builtin media handlers.
This commit is contained in:
committed by
Steve Chavez
parent
7870add603
commit
0f1ca8faac
@@ -18,6 +18,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
|||||||
- Fix OpenAPI broken docs link by @taimoorzaeem in #4080
|
- Fix OpenAPI broken docs link by @taimoorzaeem in #4080
|
||||||
- Fix OpenAPI specification incorrectly exposing GET methods for volatile functions by @joelonsql in #4174
|
- Fix OpenAPI specification incorrectly exposing GET methods for volatile functions by @joelonsql in #4174
|
||||||
- Fix empty spread embeddings return unexpected SQL error by @taimoorzaeem in #3887
|
- Fix empty spread embeddings return unexpected SQL error by @taimoorzaeem in #3887
|
||||||
|
- Fix `Accept: application/geo+json` generating an invalid query when PostGIS is not available by @steve-chavez in #4245
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
|||||||
@@ -152,6 +152,7 @@ querySchemaCache conf@AppConfig{..} = do
|
|||||||
reps <- SQL.statement conf $ dataRepresentations prepared
|
reps <- SQL.statement conf $ dataRepresentations prepared
|
||||||
mHdlers <- SQL.statement conf $ mediaHandlers prepared
|
mHdlers <- SQL.statement conf $ mediaHandlers prepared
|
||||||
tzones <- SQL.statement mempty $ timezones prepared
|
tzones <- SQL.statement mempty $ timezones prepared
|
||||||
|
hasPgis <- SQL.statement conf $ postgisFunc prepared
|
||||||
_ <-
|
_ <-
|
||||||
let sleepCall = SQL.Statement "select pg_sleep($1 / 1000.0)" (param HE.int4) HD.noResult prepared in
|
let sleepCall = SQL.Statement "select pg_sleep($1 / 1000.0)" (param HE.int4) HD.noResult prepared in
|
||||||
whenJust configInternalSCSleep (`SQL.statement` sleepCall) -- only used for testing
|
whenJust configInternalSCSleep (`SQL.statement` sleepCall) -- only used for testing
|
||||||
@@ -164,7 +165,7 @@ querySchemaCache conf@AppConfig{..} = do
|
|||||||
, dbRelationships = getOverrideRelationshipsMap rels cRels
|
, dbRelationships = getOverrideRelationshipsMap rels cRels
|
||||||
, dbRoutines = funcs
|
, dbRoutines = funcs
|
||||||
, dbRepresentations = reps
|
, dbRepresentations = reps
|
||||||
, dbMediaHandlers = HM.union mHdlers initialMediaHandlers -- the custom handlers will override the initial ones
|
, dbMediaHandlers = HM.union mHdlers $ initialMediaHandlers hasPgis -- the custom handlers will override the initial ones
|
||||||
, dbTimezones = tzones
|
, dbTimezones = tzones
|
||||||
}
|
}
|
||||||
where
|
where
|
||||||
@@ -1048,12 +1049,14 @@ allViewsKeyDependencies =
|
|||||||
having ncol = array_length(array_agg(row(col.attname, view_columns) order by pks_fks.ord), 1)
|
having ncol = array_length(array_agg(row(col.attname, view_columns) order by pks_fks.ord), 1)
|
||||||
|]
|
|]
|
||||||
|
|
||||||
initialMediaHandlers :: MediaHandlerMap
|
initialMediaHandlers :: Bool -> MediaHandlerMap
|
||||||
initialMediaHandlers =
|
initialMediaHandlers hasPostgisFunc =
|
||||||
HM.insert (RelAnyElement, MediaType.MTAny ) (BuiltinOvAggJson, MediaType.MTApplicationJSON) $
|
HM.insert (RelAnyElement, MediaType.MTAny ) (BuiltinOvAggJson, MediaType.MTApplicationJSON) $
|
||||||
HM.insert (RelAnyElement, MediaType.MTApplicationJSON) (BuiltinOvAggJson, MediaType.MTApplicationJSON) $
|
HM.insert (RelAnyElement, MediaType.MTApplicationJSON) (BuiltinOvAggJson, MediaType.MTApplicationJSON) $
|
||||||
HM.insert (RelAnyElement, MediaType.MTTextCSV ) (BuiltinOvAggCsv, MediaType.MTTextCSV) $
|
HM.insert (RelAnyElement, MediaType.MTTextCSV ) (BuiltinOvAggCsv, MediaType.MTTextCSV) $
|
||||||
HM.insert (RelAnyElement, MediaType.MTGeoJSON ) (BuiltinOvAggGeoJson, MediaType.MTGeoJSON)
|
(if hasPostgisFunc
|
||||||
|
then HM.insert (RelAnyElement, MediaType.MTGeoJSON ) (BuiltinOvAggGeoJson, MediaType.MTGeoJSON)
|
||||||
|
else mempty)
|
||||||
HM.empty
|
HM.empty
|
||||||
|
|
||||||
mediaHandlers :: Bool -> SQL.Statement AppConfig MediaHandlerMap
|
mediaHandlers :: Bool -> SQL.Statement AppConfig MediaHandlerMap
|
||||||
@@ -1139,6 +1142,35 @@ timezones = SQL.Statement sql HE.noParams decodeTimezones
|
|||||||
decodeTimezones :: HD.Result TimezoneNames
|
decodeTimezones :: HD.Result TimezoneNames
|
||||||
decodeTimezones = S.fromList <$> HD.rowList (column HD.text)
|
decodeTimezones = S.fromList <$> HD.rowList (column HD.text)
|
||||||
|
|
||||||
|
|
||||||
|
-- Find the postgis function that has the signature:
|
||||||
|
-- st_asgeojson(record,...) returns text
|
||||||
|
postgisFunc :: Bool -> SQL.Statement AppConfig Bool
|
||||||
|
postgisFunc = SQL.Statement sql params decoder
|
||||||
|
where
|
||||||
|
params =
|
||||||
|
(map escapeIdent . toList . configDbSchemas >$< arrayParam HE.text) <>
|
||||||
|
(map escapeIdent . toList . configDbExtraSearchPath >$< arrayParam HE.text)
|
||||||
|
decoder = HD.singleRow (column HD.bool)
|
||||||
|
sql = encodeUtf8 [trimming|
|
||||||
|
SELECT
|
||||||
|
exists(
|
||||||
|
SELECT
|
||||||
|
1
|
||||||
|
FROM pg_catalog.pg_proc AS p
|
||||||
|
JOIN pg_catalog.pg_depend AS d
|
||||||
|
ON d.objid = p.oid
|
||||||
|
AND d.deptype = 'e'
|
||||||
|
JOIN pg_catalog.pg_extension AS e
|
||||||
|
ON e.oid = d.refobjid
|
||||||
|
WHERE p.pronamespace = ANY($$1::regnamespace[] || $$2::regnamespace[])
|
||||||
|
AND p.proname = 'st_asgeojson'
|
||||||
|
AND e.extname = 'postgis'
|
||||||
|
AND p.proargtypes[0] = 'record'::regtype
|
||||||
|
AND pg_get_function_result(p.oid) = 'text'
|
||||||
|
);
|
||||||
|
|]
|
||||||
|
|
||||||
param :: HE.Value a -> HE.Params a
|
param :: HE.Value a -> HE.Params a
|
||||||
param = HE.param . HE.nonNullable
|
param = HE.param . HE.nonNullable
|
||||||
|
|
||||||
|
|||||||
@@ -3,11 +3,6 @@
|
|||||||
- - tag: BuiltinOvAggCsv
|
- - tag: BuiltinOvAggCsv
|
||||||
- tag: MTTextCSV
|
- tag: MTTextCSV
|
||||||
|
|
||||||
- - - tag: RelAnyElement
|
|
||||||
- tag: MTGeoJSON
|
|
||||||
- - tag: BuiltinOvAggGeoJson
|
|
||||||
- tag: MTGeoJSON
|
|
||||||
|
|
||||||
- - - tag: RelAnyElement
|
- - - tag: RelAnyElement
|
||||||
- tag: MTApplicationJSON
|
- tag: MTApplicationJSON
|
||||||
- - tag: BuiltinOvAggJson
|
- - tag: BuiltinOvAggJson
|
||||||
|
|||||||
@@ -1137,6 +1137,18 @@ def test_no_pool_connection_required_on_bad_embedding(defaultenv):
|
|||||||
assert response.status_code == 400
|
assert response.status_code == 400
|
||||||
|
|
||||||
|
|
||||||
|
def test_no_pool_connection_required_on_unavailable_postgis(defaultenv):
|
||||||
|
"no pool connection should be consumed when PostGIS is not available, the request should be quickly rejected at the plan level"
|
||||||
|
|
||||||
|
headers = {
|
||||||
|
"Accept": "application/geo+json",
|
||||||
|
}
|
||||||
|
|
||||||
|
with run(env=defaultenv, no_pool_connection_available=True) as postgrest:
|
||||||
|
response = postgrest.session.get("/projects", headers=headers)
|
||||||
|
assert response.status_code == 406
|
||||||
|
|
||||||
|
|
||||||
# https://github.com/PostgREST/postgrest/issues/2620
|
# https://github.com/PostgREST/postgrest/issues/2620
|
||||||
def test_notify_reloading_catalog_cache(defaultenv):
|
def test_notify_reloading_catalog_cache(defaultenv):
|
||||||
"notify should reload the connection catalog cache"
|
"notify should reload the connection catalog cache"
|
||||||
|
|||||||
Reference in New Issue
Block a user