cube-js / cube-js/cube

Cube SQL pg_type returns NULL instead of 0 for typsend/typoutput

Open
#10,307 2 comments 0 reactions 0 assignees View on GitHub
api:sql
Dominant language
Rust
Stars
20.8k
Forks
2.1k
Avg merge
1d 2h
Merged PRs (30d)
181

Description

# Bug Report: Cube SQL pg_type returns NULL instead of 0 for typsend/typoutput

## Summary

Postgrex/Ecto fails to connect to Cube SQL API because `pg_type` system catalog returns NULL for `typsend` and `typoutput` columns instead of 0.

## Error

```
** (ArgumentError) errors were found at the given arguments:
* 1st argument: not a binary
(stdlib) :binary.copy(nil)
(postgrex 0.21.1) lib/postgrex/types.ex:137: Postgrex.Types.build_type_info/1
(postgrex 0.21.1) lib/postgrex/protocol.ex:1092: Postgrex.Protocol.bootstrap_recv/4
(postgrex 0.21.1) lib/postgrex/protocol.ex:749: Postgrex.Protocol.handshake/3
(postgrex 0.21.1) lib/postgrex/protocol.ex:229: Postgrex.Protocol.connect_endpoints/6
```

## Root Cause

Postgrex type bootstrap queries `pg_type` to get type send/receive functions. The query expects `typsend` and `typoutput` to be OIDs (integers), but Cube returns NULL for these columns.

### Postgrex Bootstrap Query

```sql
SELECT t.oid, t.typname, t.typsend, t.typreceive, t.typoutput, t.typinput,
t.typelem, t.typbasetype, t.typnamespace, t.typdelim, COALESCE(c.reltype, 0),
COALESCE(r.rngsubtype, 0), t.typtype, t.typcategory
FROM pg_type AS t
LEFT JOIN pg_class AS c ON c.oid = t.typrelid
LEFT JOIN pg_range AS r ON r.rngtypid = t.oid
```

## Reproduction

### Query to verify the issue

```sql
SELECT t.oid, t.typname,
t.typsend IS NULL as typsend_null,
t.typoutput IS NULL as typoutput_null,
t.typreceive IS NULL as typreceive_null
FROM pg_type AS t
LIMIT 5;
```

### Current Cube Output (BROKEN)

```
oid | typname | typsend_null | typoutput_null | typreceive_null
-----+---------+--------------+----------------+-----------------
16 | bool | t | t | f
17 | bytea | t | t | f
19 | name | t | t | f
20 | int8 | t | t | f
21 | int2 | t | t | f
```

Note: `typsend` and `typoutput` are NULL (`t`), but `typreceive` correctly returns non-NULL (`f`).

### Expected Output (PostgreSQL behavior)

```
oid | typname | typsend | typoutput | typreceive
-----+---------+---------+-----------+------------
16 | bool | 2436 | 16 | 2436
17 | bytea | 2412 | 31 | 2412
19 | name | 2422 | 359 | 2422
20 | int8 | 2408 | 461 | 2408
21 | int2 | 2404 | 39 | 2404
```

All columns should return either a valid OID or 0, never NULL.

## Suggested Fix

In Cube's `pg_type` implementation, return `0` instead of `NULL` for:
- `typsend`
- `typoutput`

This is consistent with how `typreceive` already returns 0 or a valid OID.

## Affected Software

- Postgrex 0.19+ (Elixir PostgreSQL driver)
- Ecto.Adapters.Postgres (Elixir ORM)
- Any PostgreSQL client that queries `pg_type` for type metadata during connection bootstrap

## Environment

- Cube SQL API via PostgreSQL wire protocol (port 15432)
- Postgrex 0.21.1
- Ecto 3.13.x
- Elixir 1.18.3
- Erlang/OTP 27

## Related

This blocks using Ecto with Cube SQL API for querying cubes via standard PostgreSQL protocol.

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.