graphile / graphile/crystal

Functions with same name but different parameter types are silently dropped (overload detection too aggressive)

Open
#2,972 1 comment 0 reactions 0 assignees View on GitHub
✨ feature
Dominant language
TypeScript
Stars
12.9k
Forks
625
Avg merge
5h 23m
Merged PRs (30d)
24

Description

When multiple functions share the same name but have different parameter types (valid PostgreSQL overloading), PgProceduresPlugin silently drops all overloads, not just duplicates.

**Example**

```
CREATE SCHEMA computed;

CREATE FUNCTION computed.code(sales.orders) RETURNS text AS $$ ... $$ LANGUAGE sql STABLE;
CREATE FUNCTION computed.code(work.jobs) RETURNS text AS $$ ... $$ LANGUAGE sql STABLE;
CREATE FUNCTION computed.code(partner.accounts) RETURNS text AS $$ ... $$ LANGUAGE plpgsql STABLE;
```

These are three distinct PostgreSQL functions (different OIDs, different parameter types). Each takes a different table's row type as its first argument, making them valid computed column candidates for three different GraphQL types (SalesOrder, WorkJob, PartnerAccount).

Expected: All three appear as code fields on their respective GraphQL types.

Actual: None of them appear. All are silently dropped.

**Cause**

In PgProceduresPlugin, the overload check compares only pronamespace and proname, ignoring proargtypes:

```
const overload = introspection.procs.find((p) =>
p.pronamespace === pgProc.pronamespace &&
p.proname === pgProc.proname &&
p._id !== pgProc._id
);
if (overload) {
return; // skips this function entirely
}
```

Since each function finds one of the others as an "overload", all overloads are dropped.

**Why this matters**

This pattern is natural for computed columns: a function named `is_open` that works on `sales.orders`, `sales.orderlines`, and `inbound.deliverylines` is three logically separate computed columns. Each targets a different type and there's no naming conflict in the GraphQL schema.

**Possible fix**

When the first parameter is a composite (row) type for different tables, these aren't true overloads from a GraphQL perspective, they produce fields on different types. The check could be relaxed to allow functions with the same name when their first parameter refers to a different table, or the resource name could include the table name to disambiguate (e.g., orders_code, jobs_code).

**Workaround**

Rename each function to include the table name prefix: `computed.orders_code(sales.orders)`, `computed.jobs_code(work.jobs)`, etc. However, this is a lot less nice for SQL-usage of the database. What was previously:
```
SELECT orders.code FROM sales.orders
-- or
SELECT computed.code(order.*) FROM sales.orders
```
Must now become:
```
SELECT computed.orders_code(order.*) AS code FROM sales.orders
```

**Versions**

- postgraphile 5.0.0-rc.9
- graphile-build-pg 5.0.0-rc.7

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.