Skip to content

fix(metadata): tolerate NULL catalog scans on openGauss - #592

Closed
yimiaoxiehou wants to merge 2 commits into
xo:release-21from
yimiaoxiehou:fix/open-gauss-null-scan
Closed

yimiaoxiehou wants to merge 2 commits into
xo:release-21from
yimiaoxiehou:fix/open-gauss-null-scan

Conversation

@yimiaoxiehou

Copy link
Copy Markdown

Problem

On openGauss, every metadata command fails outright:

$ usql postgres://host:5432/db
pg:root@db=> \dt
error: failed to list tables: sql: Scan error on column index 5,
name "Description": converting NULL to string is unsupported

\d, \df, \dp and \l fail the same way.

Root cause

The readers guard nullable catalog columns with COALESCE(x, '') because
database/sql cannot convert NULL into a string or int. That guard is
useless under openGauss' Oracle-compatible mode (sql_compatibility=A),
where the empty string literal '' is itself NULL:

select ('' is null);             -- t
select coalesce(null::text,'');   -- NULL  (even ''::text does not help)

so COALESCE(x, '') evaluates to COALESCE(x, NULL) and the NULL still
reaches the scanner. An empty string cannot be represented at all under
these semantics, so the fix has to happen on the scan side rather than in
the SQL.

Fix

Add nullStr / nullInt / nullBool / nullBoolVal scan targets that
absorb NULL, and route every scan in the information_schema and
postgres metadata readers through them. The SQL is unchanged, so the
queries stay correct under both PostgreSQL and openGauss semantics.

nullInt deliberately replicates database/sql's asString conversion so
it accepts exactly the value types the plain *int destinations it replaces
accepted — otherwise a driver returning a number as text or as uint64
would start failing on the other databases sharing this reader (MySQL,
SQL Server, ...), which never had this problem. nullStr and nullBool
already matched the standard library, whose *string branch accepts only
string and []byte.

Also accept int64 for is_grantable: information_schema.yes_or_no is a
domain over boolean in PostgreSQL but is reported as a numeric YES/NO by
openGauss, which otherwise broke \dp with cannot scan int64 into bool.

Verification

Against openGauss 6.0.3 (sql_compatibility=A), 23 metadata commands —
\l \dn \dt \dt+ \di \d \d+ \dT \dtT \df \dp \dv \ds \z \dC \dD \dx \dew \deu \sf and pattern variants — all pass with no Scan errors. Output was also
checked for correctness, not just absence of errors: comments, column
defaults and nullability all render correctly.

nullscan_test.go asserts the targets accept exactly the value types
database/sql converts while absorbing NULL. Note that it cannot run
without a working Docker daemon, as TestMain in this package
unconditionally starts database containers.

Target branch

Opened against release-21 because main no longer contains this code:
drivers/metadata has been removed there (no obj_description or
COALESCE(column_default remain anywhere in the repository). The
0.21.x line is what still needs this fix.

usql guards nullable catalog columns with COALESCE(x, '') because
database/sql cannot convert NULL into a string or int. On openGauss
running in Oracle-compatible mode (sql_compatibility=A) the empty string
literal '' is itself NULL, so COALESCE(x, '') evaluates to
COALESCE(x, NULL) and the NULL still reaches the scanner. Every metadata
command aborts with:

  failed to list tables: sql: Scan error on column index 5,
  name "Description": converting NULL to string is unsupported

An empty string cannot be represented at all under these semantics, so
the fix has to happen on the scan side. Add nullStr/nullInt/nullBool/
nullBoolVal scanner targets that absorb NULL, and route every scan in the
information_schema and postgres metadata readers through them. The SQL is
unchanged, so the queries remain correct under both PostgreSQL and
openGauss semantics.

Also accept int64 for is_grantable: information_schema.yes_or_no is a
domain over boolean in PostgreSQL, but openGauss reports it as a numeric
YES/NO, which used to break \dp with "cannot scan int64 into bool".

Verified against openGauss 6.0.3: \l \dn \dt \dt+ \di \d \d+ \dT \dtT
\df \dp \dv \ds \z \dC \dD \dx \dew \deu \sf all pass, no Scan errors.
The NULL-tolerant scan targets must not be stricter than the plain
destinations they replace, or they would introduce new failures on the
other databases sharing this information_schema reader (MySQL, SQL
Server, ...), which never had this problem.

database/sql converts into *int by rendering the driver value with
asString and parsing the result, so it accepts numeric-as-text, bool and
every integer/unsigned/float kind. nullInt only handled int64, int32,
float64 and []byte, so a driver returning a value as, say, a string or
uint64 would now fail where it previously worked. Replicate asString
(strconv + reflect) and parse from that, matching the standard library
exactly while still absorbing NULL.

nullStr and nullBool are unaffected: database/sql's *string branch also
accepts only string and []byte, which is what they already did.

Adds nullscan_test.go asserting the targets accept exactly the value
types database/sql converts, and that NULL is absorbed. Note the test
cannot run without a working Docker daemon: TestMain in this package
unconditionally starts database containers.
@kenshaw

kenshaw commented Oct 15, 2026

Copy link
Copy Markdown
Member

@yimiaoxiehou there will not be any further releases on the release-21 branch, barring a security issue/fix. There is a new database meta model being used on the main branch that uses the dbmeta project/repo.

If openGauss needs its own metadata model, please point a coding agent at that repo and instruct (prompt) it to build a DIALECT for that database. If it connects using the PG driver, it would be another "flavor" of the PostgreSQL DIALECT, and is well doxumented. I will make a point to add this, but otherwise rejecting this PR as significantly different plans are in motion already.

That said, I do appreciate the contribution!

@kenshaw kenshaw closed this Oct 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants