Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions pkg/sql/logictest/testdata/logic_test/pgoidtype
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,27 @@ SELECT
----
12345 12345 12345 12345 12345

# Regression test for #171257. A built-in function OID that names a "private"
# helper function (defined via makePrivate, e.g. the regression-aggregate final
# functions) must cast to its bare pg_catalog name -- not a spuriously
# "pg_catalog."-qualified name, and never the bare numeric OID. These helpers are
# excluded from builtins.AllBuiltinNames, so the by-name pg_catalog.pg_proc
# population omits them; the visibility lookup therefore found no match and
# wrongly schema-qualified them (or, with no database in scope, errored and let
# the OID render as a number). OID 56 is final_regr_syy; see
# pkg/sql/sem/builtins/fixed_oids.go.
query TTT
SELECT 56::REGPROC::STRING, 56::REGPROCEDURE::STRING, 56::OID::REGPROC::STRING
----
final_regr_syy final_regr_syy final_regr_syy

# The 'name'::reg* parse path must agree with the OID cast path: the optimizer
# interns DOids by OID alone, so divergent names would corrupt round-trips.
query TT
SELECT 'final_regr_syy'::REGPROC::STRING, 'final_regr_syy'::REGPROC::OID::REGPROC::STRING
----
final_regr_syy final_regr_syy

query T
PREPARE regression_56193 AS SELECT $1::regclass;
EXECUTE regression_56193('regression_53686"'::regclass)
Expand Down
29 changes: 29 additions & 0 deletions pkg/sql/resolve_oid.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"github.com/cockroachdb/cockroach/pkg/sql/lexbase"
"github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgcode"
"github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgerror"
"github.com/cockroachdb/cockroach/pkg/sql/sem/catid"
"github.com/cockroachdb/cockroach/pkg/sql/sem/tree"
"github.com/cockroachdb/cockroach/pkg/sql/sessiondata"
"github.com/cockroachdb/cockroach/pkg/sql/types"
Expand All @@ -38,6 +39,34 @@ func (p *planner) ResolveOIDFromString(
func (p *planner) ResolveOIDFromOID(
ctx context.Context, resultType *types.T, toResolve *tree.DOid,
) (_ *tree.DOid, errSafeToIgnore bool, _ error) {
// Built-in functions live in pg_catalog, which is always implicitly in the
// search path, so Postgres's regprocout emits their bare name. Resolve them
// from the in-memory function registry rather than through resolveOID's
// catalog query, which determines visibility by looking up
// pg_catalog.pg_proc by name. The by-name population of that virtual table
// is built from builtins.AllBuiltinNames and omits private aggregate/window
// helper functions (e.g. final_regr_syy), so resolveOID's visibility check
// finds no match and spuriously schema-qualifies them; worse, when no
// database is in scope the query errors and the OID renders as a bare
// number. Resolving in memory keeps the cast deterministic regardless of
// session and execution context. User-defined functions still flow through
// resolveOID for search-path-aware schema qualification.
switch resultType.Oid() {
case oid.T_regproc, oid.T_regprocedure:
if !catid.IsOIDUserDefined(toResolve.Oid) {
name, _, err := p.ResolveFunctionByOID(ctx, toResolve.Oid)
if err != nil {
if errors.Is(err, tree.ErrRoutineUndefined) {
// The OID is in the built-in range but names no known
// function; leave the DOid nameless so it renders as the
// bare numeric OID, matching Postgres.
return tree.NewDOidWithType(toResolve.Oid, resultType), true, nil //nolint:returnerrcheck
}
return nil, false, err
}
return tree.NewDOidWithTypeAndName(toResolve.Oid, resultType, name.Object()), true, nil
}
}
return resolveOID(
ctx, p.Txn(),
p.InternalSQLTxn(),
Expand Down
Loading