hasura / hasura/graphql-engine
Bug: Hasura "analyze" not working for custom function with custom type not in search_path
- Dominant language
- TypeScript
- Stars
- 32.1k
- Forks
- 3k
- PR merge metrics
- PR metrics pending
Description
# Issue
"Analyze" on a query of a tracked custom function that has an input variable of a custom type fails, if the input type is not in the postgres role search_path.
# Test-case
## Error in UI
This query works as intended and can be analyzed
```
query MyQuery {
entity_for_points_works(args: {in_points: "{\"(1,1)\"}"}) {
range
type_id
}
}
```

This query works as intended but can not be analyzed
```
query MyQuery {
entity_for_points_analyzebroken(args: {in_points: "{\"(1,1)\"}"}) {
range
type_id
}
}
```
When clicking "analyze" I receive this:

```
Unable to fetch: {"path":"$","error":"type \"_input_type_not_in_searchpath\" does not exist","code":"constraint-error"}.
```
Server log:
```
{"type":"http-log","timestamp":"2020-03-26T14:13:03.672+0000","level":"error","detail":{"operation":{"user_vars":{"x-hasura-role":"admin"},"error":{"path":"$","error":"type \"_input_type_not_in_searchpath\" does not exist","code":"constraint-error"},"request_id":"bf825069-5463-4753-92db-88ac0302c289","response_size":102,"query":{"user":{"x-hasura-role":"admin"},"query":{"operationName":"MyQuery","query":"query MyQuery { entity_for_points_analyzebroken(args: {in_points:\"{\"(1,1)\"}\"}) { range type_id } }"}}},"http_info":{"status":400,"http_version":"HTTP/1.1","url":"/v1/graphql/explain","ip":"172.17.0.1","method":"POST","content_encoding":null}}}
{"type":"http-log","timestamp":"2020-03-26T14:13:19.847+0000","level":"error","detail":{"operation":{"user_vars":{"x-hasura-role":"admin"},"error":{"path":"$","error":"type \"_input_type_not_in_searchpath\" does not exist","code":"constraint-error"},"request_id":"35ee831c-8d7b-4713-88fd-1ee0f2db577d","response_size":102,"query":{"user":{"x-hasura-role":"admin"},"query":{"operationName":"MyQuery","query":"query MyQuery { entity_for_points_analyzebroken(args: {in_points:\"{\"(1,1)\"}\"}) { range type_id } }"}}},"http_info":{"status":400,"http_version":"HTTP/1.1","url":"/v1/graphql/explain","ip":"172.17.0.1","method":"POST","content_encoding":null}}}
```
## Postgres config
Version: 9.6.14
DB Setup:
```SQL
-- create a schema outside of search path
DROP SCHEMA not_in_searchpath CASCADE;
CREATE SCHEMA not_in_searchpath;
-- create a type outside of search path
DROP TYPE IF EXISTS not_in_searchpath.input_type_not_in_searchpath CASCADE;
CREATE TYPE not_in_searchpath.input_type_not_in_searchpath AS (
point int,
type_id integer
);
-- create a type inside of search path
DROP TYPE IF EXISTS public.input_type CASCADE;
CREATE TYPE public.input_type AS (
point int,
type_id integer
);
-- create an example table with example data
-- this has int4ranges, my usecase included having to provide a function to overlap points with these
DROP TABLE public.entity CASCADE;
CREATE TABLE public.entity (
range int4range,
type_id integer
);
INSERT INTO public.entity (range, type_id) VALUES (int4range(1,2,'[]'), 1);
INSERT INTO public.entity (range, type_id) VALUES (int4range(7,8,'[]'), 1);
-- this function works as intended, and overlaps given input points and type_ids with the ranges in the table to find hits
CREATE OR REPLACE FUNCTION public.entity_for_points_works(in_points public.input_type[])
RETURNS SETOF public.entity
LANGUAGE plpgsql
STABLE AS $$
BEGIN
RETURN QUERY
WITH spec AS (SELECT * FROM UNNEST(in_points))
SELECT distinct
et.*
FROM
public.entity et
JOIN spec sp ON (
int4range(sp.point-5,sp.point+5,'[]') && et.range
AND et.type_id = sp.type_id
);
END
$$;
-- this function does not work as intended, because it uses not_in_searchpath.input_type_not_in_searchpath
CREATE OR REPLACE FUNCTION public.entity_for_points_analyzebroken(in_points not_in_searchpath.input_type_not_in_searchpath[])
RETURNS SETOF public.entity
LANGUAGE plpgsql
STABLE AS $$
BEGIN
RETURN QUERY
WITH spec AS (SELECT * FROM UNNEST(in_points))
SELECT distinct
et.*
FROM
public.entity et
JOIN spec sp ON (
int4range(sp.point-5,sp.point+5,'[]') && et.range
AND et.type_id = sp.type_id
);
END
$$;
-- confirm both functions work on postgres
select * from public.entity_for_points_works('{"(1,1)"}');
select * from public.entity_for_points_analyzebroken('{"(1,1)"}');
```
## Hasura config
Running: Hasura v1.1.0 on docker via
```
docker run -p 8080:8080 \
-v /my/path/tmp_metadata:/hasura-migrations \
-e HASURA_GRAPHQL_DATABASE_URL="postgres://postgres:postgres@host.docker.internal:5435/postgres" \
-e HASURA_GRAPHQL_ENABLE_CONSOLE=true \
hasura/graphql-engine:latest.cli-migrations
```
with the file `tmp_metadata/metadata.json`:
[metadata.json.zip](https://github.com/hasura/graphql-engine/files/4387638/metadata.json.zip)
Contributor guide
Assessment
This issue has not been assessed yet.