diff --git a/pkg/ccl/logictestccl/tests/3node-tenant/generated_test.go b/pkg/ccl/logictestccl/tests/3node-tenant/generated_test.go index fdb4c2b61632..85316a727873 100644 --- a/pkg/ccl/logictestccl/tests/3node-tenant/generated_test.go +++ b/pkg/ccl/logictestccl/tests/3node-tenant/generated_test.go @@ -1493,6 +1493,13 @@ func TestTenantLogic_redact_descriptor( runLogicTest(t, "redact_descriptor") } +func TestTenantLogic_refcursor( + t *testing.T, +) { + defer leaktest.AfterTest(t)() + runLogicTest(t, "refcursor") +} + func TestTenantLogic_rename_atomic( t *testing.T, ) { diff --git a/pkg/sql/backfill/backfill.go b/pkg/sql/backfill/backfill.go index c1db5289f33d..fdc4c255133a 100644 --- a/pkg/sql/backfill/backfill.go +++ b/pkg/sql/backfill/backfill.go @@ -236,6 +236,7 @@ func (cb *ColumnBackfiller) InitForDistributedUse( // Set up a SemaContext to type check the default and computed expressions. semaCtx := tree.MakeSemaContext() semaCtx.TypeResolver = &resolver + semaCtx.UnsupportedTypeChecker = eval.NewUnsupportedTypeChecker(evalCtx.Settings.Version) var err error defaultExprs, err = schemaexpr.MakeDefaultExprs( ctx, cb.added, &transform.ExprTransformContext{}, evalCtx, &semaCtx, @@ -670,6 +671,7 @@ func (ib *IndexBackfiller) InitForDistributedUse( // Set up a SemaContext to type check the default and computed expressions. semaCtx := tree.MakeSemaContext() semaCtx.TypeResolver = &resolver + semaCtx.UnsupportedTypeChecker = eval.NewUnsupportedTypeChecker(evalCtx.Settings.Version) // Convert any partial index predicate strings into expressions. predicates, colExprs, referencedColumns, err = constructExprs( ctx, desc, ib.added, ib.cols, ib.addedCols, ib.computedCols, evalCtx, &semaCtx, diff --git a/pkg/sql/catalog/colinfo/col_type_info.go b/pkg/sql/catalog/colinfo/col_type_info.go index 4dff7bbd78a4..42f30f4a16af 100644 --- a/pkg/sql/catalog/colinfo/col_type_info.go +++ b/pkg/sql/catalog/colinfo/col_type_info.go @@ -78,6 +78,14 @@ func ValidateColumnDefType(ctx context.Context, version clusterversion.Handle, t return pgerror.Newf(pgcode.Syntax, `invalid locale %s`, t.Locale()) } } + if t.Oid() == oid.T_refcursor { + if !version.IsActive(ctx, clusterversion.V23_2) { + return pgerror.Newf( + pgcode.FeatureNotSupported, + "refcursor not supported until version 23.2", + ) + } + } case types.DecimalFamily: switch { diff --git a/pkg/sql/catalog/colinfo/column_type_properties_test.go b/pkg/sql/catalog/colinfo/column_type_properties_test.go index 9a1d1a0310df..b90778214d23 100644 --- a/pkg/sql/catalog/colinfo/column_type_properties_test.go +++ b/pkg/sql/catalog/colinfo/column_type_properties_test.go @@ -55,6 +55,7 @@ func TestCanHaveCompositeKeyEncoding(t *testing.T) { {types.Jsonb, true}, {types.Name, false}, {types.Oid, false}, + {types.RefCursor, false}, {types.String, false}, {types.StringArray, false}, {types.Time, false}, diff --git a/pkg/sql/create_type.go b/pkg/sql/create_type.go index 83bd3910171b..06abc86f62f7 100644 --- a/pkg/sql/create_type.go +++ b/pkg/sql/create_type.go @@ -423,6 +423,10 @@ func CreateCompositeTypeDesc( if err != nil { return nil, err } + err = tree.CheckUnsupportedType(params.ctx, ¶ms.p.semaCtx, typ) + if err != nil { + return nil, err + } if typ.UserDefined() { return nil, unimplemented.NewWithIssue(91779, "composite types that reference user-defined types not yet supported") diff --git a/pkg/sql/logictest/testdata/logic_test/grant_table b/pkg/sql/logictest/testdata/logic_test/grant_table index 1e291a6a5210..20dc86ab94ff 100644 --- a/pkg/sql/logictest/testdata/logic_test/grant_table +++ b/pkg/sql/logictest/testdata/logic_test/grant_table @@ -492,6 +492,12 @@ test pg_catalog record root test pg_catalog record[] admin ALL false test pg_catalog record[] public USAGE false test pg_catalog record[] root ALL false +test pg_catalog refcursor admin ALL false +test pg_catalog refcursor public USAGE false +test pg_catalog refcursor root ALL false +test pg_catalog refcursor[] admin ALL false +test pg_catalog refcursor[] public USAGE false +test pg_catalog refcursor[] root ALL false test pg_catalog regclass admin ALL false test pg_catalog regclass public USAGE false test pg_catalog regclass root ALL false @@ -709,6 +715,10 @@ test pg_catalog record admin ALL false test pg_catalog record root ALL false test pg_catalog record[] admin ALL false test pg_catalog record[] root ALL false +test pg_catalog refcursor admin ALL false +test pg_catalog refcursor root ALL false +test pg_catalog refcursor[] admin ALL false +test pg_catalog refcursor[] root ALL false test pg_catalog regclass admin ALL false test pg_catalog regclass root ALL false test pg_catalog regclass[] admin ALL false @@ -1285,6 +1295,10 @@ a pg_catalog record admin ALL a pg_catalog record root ALL false a pg_catalog record[] admin ALL false a pg_catalog record[] root ALL false +a pg_catalog refcursor admin ALL false +a pg_catalog refcursor root ALL false +a pg_catalog refcursor[] admin ALL false +a pg_catalog refcursor[] root ALL false a pg_catalog regclass admin ALL false a pg_catalog regclass root ALL false a pg_catalog regclass[] admin ALL false @@ -1457,6 +1471,10 @@ defaultdb pg_catalog record admin ALL defaultdb pg_catalog record root ALL false defaultdb pg_catalog record[] admin ALL false defaultdb pg_catalog record[] root ALL false +defaultdb pg_catalog refcursor admin ALL false +defaultdb pg_catalog refcursor root ALL false +defaultdb pg_catalog refcursor[] admin ALL false +defaultdb pg_catalog refcursor[] root ALL false defaultdb pg_catalog regclass admin ALL false defaultdb pg_catalog regclass root ALL false defaultdb pg_catalog regclass[] admin ALL false @@ -1629,6 +1647,10 @@ postgres pg_catalog record admin ALL postgres pg_catalog record root ALL false postgres pg_catalog record[] admin ALL false postgres pg_catalog record[] root ALL false +postgres pg_catalog refcursor admin ALL false +postgres pg_catalog refcursor root ALL false +postgres pg_catalog refcursor[] admin ALL false +postgres pg_catalog refcursor[] root ALL false postgres pg_catalog regclass admin ALL false postgres pg_catalog regclass root ALL false postgres pg_catalog regclass[] admin ALL false @@ -1801,6 +1823,10 @@ system pg_catalog record admin ALL system pg_catalog record root ALL false system pg_catalog record[] admin ALL false system pg_catalog record[] root ALL false +system pg_catalog refcursor admin ALL false +system pg_catalog refcursor root ALL false +system pg_catalog refcursor[] admin ALL false +system pg_catalog refcursor[] root ALL false system pg_catalog regclass admin ALL false system pg_catalog regclass root ALL false system pg_catalog regclass[] admin ALL false @@ -2321,6 +2347,10 @@ test pg_catalog record admin ALL test pg_catalog record root ALL false test pg_catalog record[] admin ALL false test pg_catalog record[] root ALL false +test pg_catalog refcursor admin ALL false +test pg_catalog refcursor root ALL false +test pg_catalog refcursor[] admin ALL false +test pg_catalog refcursor[] root ALL false test pg_catalog regclass admin ALL false test pg_catalog regclass root ALL false test pg_catalog regclass[] admin ALL false diff --git a/pkg/sql/logictest/testdata/logic_test/mixed_version_refcursor b/pkg/sql/logictest/testdata/logic_test/mixed_version_refcursor new file mode 100644 index 000000000000..d3a342036dfc --- /dev/null +++ b/pkg/sql/logictest/testdata/logic_test/mixed_version_refcursor @@ -0,0 +1,185 @@ +# LogicTest: cockroach-go-testserver-upgrade-to-master + +statement ok +CREATE TABLE xy (x INT, y INT); + +# ---------------------------------------------------------------------- +# Test REFCURSOR references with all nodes running old binaries. +# ---------------------------------------------------------------------- + +subtest all_old_cast + +# Cast to REFCURSOR. +statement error pgcode 42704 pq: type \"refcursor\" does not exist +SELECT 'foo'::REFCURSOR; + +# Cast to REFCURSOR using the vectorized engine. +statement error pgcode 42704 pq: type \"refcursor\" does not exist +SELECT 'foo'::REFCURSOR FROM generate_series(1, 100) LIMIT 1; + +subtest all_old_table + +# Table that references REFCURSOR. +statement error pgcode 42704 pq: type \"refcursor\" does not exist +CREATE TABLE t (x REFCURSOR); + +# Add a REFCURSOR column. +statement error pgcode 42704 pq: type \"refcursor\" does not exist +ALTER TABLE xy ADD COLUMN curs REFCURSOR; + +# Alter a column type to REFCURSOR. +statement ok +SET enable_experimental_alter_column_type_general=true; + +statement error pgcode 42704 pq: type \"refcursor\" does not exist +ALTER TABLE xy ALTER COLUMN y TYPE REFCURSOR; + +# Create a partial index that uses the REFCURSOR type. +statement error pgcode 42704 pq: type \"refcursor\" does not exist +CREATE INDEX part ON xy (x) WHERE y::REFCURSOR < 'foo'; + +# Add a check constraint that uses the REFCURSOR type. +statement error pgcode 42704 pq: type \"refcursor\" does not exist +ALTER TABLE xy ADD CONSTRAINT bar CHECK (y::REFCURSOR < 'baz'); + +subtest all_old_type + +# UDT that references REFCURSOR. +statement error pgcode 42704 pq: type \"refcursor\" does not exist +CREATE TYPE typ AS (x INT, y REFCURSOR); + +subtest all_old_function + +# Function that returns REFCURSOR. +statement error pgcode 42704 pq: type \"refcursor\" does not exist +CREATE OR REPLACE FUNCTION f() RETURNS REFCURSOR AS $$ + SELECT 'foo'; +$$ LANGUAGE SQL; + +# Function that takes REFCURSOR argument. +statement error pgcode 42704 pq: type \"refcursor\" does not exist +CREATE OR REPLACE FUNCTION f(curs REFCURSOR) RETURNS STRING AS $$ + SELECT curs; +$$ LANGUAGE SQL; + +# Function that references REFCURSOR internally. +statement error pgcode 42704 pq: type \"refcursor\" does not exist +CREATE OR REPLACE FUNCTION f() RETURNS INT AS $$ + SELECT 'foo'::REFCURSOR; + SELECT 0; +$$ LANGUAGE SQL; + +# Function that returns a composite type with REFCURSOR component. +statement error pgcode 42704 pq: type \"refcursor\" does not exist +CREATE FUNCTION f() RETURNS RECORD AS $$ + SELECT (1, 'foo'::REFCURSOR, true); +$$ LANGUAGE SQL; + +subtest end + +# ---------------------------------------------------------------------- +# Verify that REFCURSOR is not allowed after upgrading the gateway. +# ---------------------------------------------------------------------- + +upgrade 0 + +user root nodeidx=0 + +subtest upgrade_one_cast + +# Cast to REFCURSOR. +statement error pgcode 0A000 pq: refcursor not supported until version 23.2 +SELECT 'foo'::REFCURSOR; + +# Cast to REFCURSOR using the vectorized engine. +statement error pgcode 0A000 pq: refcursor not supported until version 23.2 +SELECT 'foo'::REFCURSOR FROM generate_series(1, 100) LIMIT 1; + +subtest upgrade_one_table + +# Table that references REFCURSOR. +statement error pgcode 0A000 pq: refcursor not supported until version 23.2 +CREATE TABLE t (x REFCURSOR); + +# Add a REFCURSOR column. +statement error pgcode 0A000 pq: refcursor not supported until version 23.2 +ALTER TABLE xy ADD COLUMN curs REFCURSOR; + +# Alter a column type to REFCURSOR. +statement ok +SET enable_experimental_alter_column_type_general=true; + +statement error pgcode 0A000 pq: refcursor not supported until version 23.2 +ALTER TABLE xy ALTER COLUMN y TYPE REFCURSOR; + +# Create a partial index that uses the REFCURSOR type. +statement error pgcode 0A000 pq: refcursor not supported until version 23.2 +CREATE INDEX part ON xy (x) WHERE y::REFCURSOR < 'foo'; + +# Add a check constraint that uses the REFCURSOR type. +statement error pgcode 0A000 pq: refcursor not supported until version 23.2 +ALTER TABLE xy ADD CONSTRAINT bar CHECK (y::REFCURSOR < 'baz'); + +subtest upgrade_one_type + +# UDT that references REFCURSOR. +statement error pgcode 0A000 pq: refcursor not supported until version 23.2 +CREATE TYPE typ AS (x INT, y REFCURSOR); + +subtest upgrade_one_function + +# Function that returns REFCURSOR. +statement error pgcode 0A000 pq: refcursor not supported until version 23.2 +CREATE OR REPLACE FUNCTION f() RETURNS REFCURSOR AS $$ + SELECT 'foo'; +$$ LANGUAGE SQL; + +statement error pgcode 0A000 pq: refcursor not supported until version 23.2 +CREATE OR REPLACE FUNCTION f() RETURNS REFCURSOR AS $$ + BEGIN + RETURN 'foo'; + END +$$ LANGUAGE PLpgSQL; + +# Function that takes REFCURSOR argument. +statement error pgcode 0A000 pq: refcursor not supported until version 23.2 +CREATE OR REPLACE FUNCTION f(curs REFCURSOR) RETURNS INT AS $$ + SELECT 0; +$$ LANGUAGE SQL; + +statement error pgcode 0A000 pq: refcursor not supported until version 23.2 +CREATE OR REPLACE FUNCTION f(curs REFCURSOR) RETURNS INT AS $$ + BEGIN + RETURN 0; + END +$$ LANGUAGE PLpgSQL; + +# Function that references REFCURSOR internally. +statement error pgcode 0A000 pq: refcursor not supported until version 23.2 +CREATE OR REPLACE FUNCTION f() RETURNS INT AS $$ + SELECT 'foo'::REFCURSOR; + SELECT 0; +$$ LANGUAGE SQL; + +statement error pgcode 0A000 pq: refcursor not supported until version 23.2 +CREATE OR REPLACE FUNCTION f() RETURNS INT AS $$ + BEGIN + SELECT 'foo'::REFCURSOR; + RETURN 0; + END +$$ LANGUAGE PLpgSQL; + +# Function that returns a composite type with REFCURSOR component. +statement error pgcode 0A000 pq: refcursor not supported until version 23.2 +CREATE FUNCTION f() RETURNS RECORD AS $$ + SELECT (1, 'foo'::REFCURSOR, true); +$$ LANGUAGE SQL; + +statement error pgcode 0A000 pq: refcursor not supported until version 23.2 +CREATE FUNCTION f() RETURNS RECORD AS $$ + BEGIN + RETURN (1, 'foo'::REFCURSOR, true); + END +$$ LANGUAGE PLpgSQL; + +subtest end diff --git a/pkg/sql/logictest/testdata/logic_test/pg_catalog b/pkg/sql/logictest/testdata/logic_test/pg_catalog index 86ff7d72d5e8..6951579dbc15 100644 --- a/pkg/sql/logictest/testdata/logic_test/pg_catalog +++ b/pkg/sql/logictest/testdata/logic_test/pg_catalog @@ -1856,6 +1856,8 @@ oid typname typnamespace typowner typlen typbyval typty 1562 varbit 4294967109 NULL -1 false b 1563 _varbit 4294967109 NULL -1 false b 1700 numeric 4294967109 NULL -1 false b +1790 refcursor 4294967109 NULL -1 false b +2201 _refcursor 4294967109 NULL -1 false b 2202 regprocedure 4294967109 NULL 4 true b 2205 regclass 4294967109 NULL 4 true b 2206 regtype 4294967109 NULL 4 true b @@ -1969,6 +1971,8 @@ oid typname typcategory typispreferred typisdefined typdel 1562 varbit V false true , 0 0 1563 1563 _varbit A false true , 0 1562 0 1700 numeric N false true , 0 0 1231 +1790 refcursor S false true , 0 0 2201 +2201 _refcursor A false true , 0 1790 0 2202 regprocedure N false true , 0 0 2207 2205 regclass N false true , 0 0 2210 2206 regtype N false true , 0 0 2211 @@ -2082,6 +2086,8 @@ oid typname typinput typoutput typreceive 1562 varbit varbit_in varbit_out varbit_recv varbit_send 0 0 0 1563 _varbit array_in array_out array_recv array_send 0 0 0 1700 numeric numeric_in numeric_out numeric_recv numeric_send 0 0 0 +1790 refcursor refcursorin refcursorout refcursorrecv refcursorsend 0 0 0 +2201 _refcursor array_in array_out array_recv array_send 0 0 0 2202 regprocedure regprocedurein regprocedureout regprocedurerecv regproceduresend 0 0 0 2205 regclass regclassin regclassout regclassrecv regclasssend 0 0 0 2206 regtype regtypein regtypeout regtyperecv regtypesend 0 0 0 @@ -2195,6 +2201,8 @@ oid typname typalign typstorage typnotnull typbasetype ty 1562 varbit NULL NULL false 0 -1 1563 _varbit NULL NULL false 0 -1 1700 numeric NULL NULL false 0 -1 +1790 refcursor NULL NULL false 0 -1 +2201 _refcursor NULL NULL false 0 -1 2202 regprocedure NULL NULL false 0 -1 2205 regclass NULL NULL false 0 -1 2206 regtype NULL NULL false 0 -1 @@ -2308,6 +2316,8 @@ oid typname typndims typcollation typdefaultbin typdefault 1562 varbit 0 0 NULL NULL NULL 1563 _varbit 0 0 NULL NULL NULL 1700 numeric 0 0 NULL NULL NULL +1790 refcursor 0 3403232968 NULL NULL NULL +2201 _refcursor 0 3403232968 NULL NULL NULL 2202 regprocedure 0 0 NULL NULL NULL 2205 regclass 0 0 NULL NULL NULL 2206 regtype 0 0 NULL NULL NULL diff --git a/pkg/sql/logictest/testdata/logic_test/pg_lsn_mixed b/pkg/sql/logictest/testdata/logic_test/pg_lsn_mixed index 41e80a673aa8..a1ce07d46a2b 100644 --- a/pkg/sql/logictest/testdata/logic_test/pg_lsn_mixed +++ b/pkg/sql/logictest/testdata/logic_test/pg_lsn_mixed @@ -1,8 +1,163 @@ -# LogicTest: local-mixed-22.2-23.1 -# TODO(otan): add tests for mixed 23.1-23.2. +# LogicTest: cockroach-go-testserver-upgrade-to-master -statement error must be finalized to use pg_lsn -SELECT '1010F/AAAA'::text::pg_lsn +statement ok +CREATE TABLE xy (x INT, y INT); -statement error pg_lsn not supported until version 23.2 -CREATE TABLE pg_lsn_table(id pg_lsn, val pg_lsn) +# ---------------------------------------------------------------------- +# Test PG_LSN references with all nodes running old binaries. +# ---------------------------------------------------------------------- + +subtest all_old_cast + +# Cast to PG_LSN. +statement error pgcode 0A000 unimplemented: this syntax +SELECT 'A01F0/1AAA'::PG_LSN; + +# Cast to PG_LSN using the vectorized engine. +statement error pgcode 0A000 unimplemented: this syntax +SELECT 'a01f0/1aaa'::PG_LSN FROM generate_series(1, 100) LIMIT 1; + +subtest all_old_table + +# Table that references PG_LSN. +statement error pgcode 0A000 unimplemented: this syntax +CREATE TABLE t (x PG_LSN); + +# Add a PG_LSN column. +statement error pgcode 0A000 unimplemented: this syntax +ALTER TABLE xy ADD COLUMN curs PG_LSN; + +# Alter a column type to PG_LSN. +statement ok +SET enable_experimental_alter_column_type_general=true; + +statement error pgcode 0A000 unimplemented: this syntax +ALTER TABLE xy ALTER COLUMN y TYPE PG_LSN; + +# Create a partial index that uses the PG_LSN type. +statement error pgcode 0A000 unimplemented: this syntax +CREATE INDEX part ON xy (x) WHERE y::PG_LSN < 'a01f0/1aaa'; + +# Add a check constraint that uses the PG_LSN type. +statement error pgcode 0A000 unimplemented: this syntax +ALTER TABLE xy ADD CONSTRAINT bar CHECK (y::PG_LSN < 'fffff100/100'); + +subtest all_old_type + +# UDT that references PG_LSN. +statement error pgcode 0A000 unimplemented: this syntax +CREATE TYPE typ AS (x INT, y PG_LSN); + +subtest all_old_function + +# Function that returns PG_LSN. +statement error pgcode 0A000 unimplemented: this syntax +CREATE OR REPLACE FUNCTION f() RETURNS PG_LSN AS $$ + SELECT 'a01f0/1aaa'; +$$ LANGUAGE SQL; + +# Function that takes PG_LSN argument. +statement error pgcode 0A000 unimplemented: this syntax +CREATE OR REPLACE FUNCTION f(curs PG_LSN) RETURNS STRING AS $$ + SELECT curs; +$$ LANGUAGE SQL; + +# Function that references PG_LSN internally. +statement error pgcode 0A000 unimplemented: this syntax +CREATE OR REPLACE FUNCTION f() RETURNS INT AS $$ + SELECT 'a01f0/1aaa'::PG_LSN; + SELECT 0; +$$ LANGUAGE SQL; + +# Function that returns a composite type with PG_LSN component. +statement error pgcode 0A000 unimplemented: this syntax +CREATE FUNCTION f() RETURNS RECORD AS $$ + SELECT (1, 'a01f0/1aaa'::PG_LSN, true); +$$ LANGUAGE SQL; + +subtest end + +# ---------------------------------------------------------------------- +# Verify that PG_LSN is not allowed after upgrading the gateway. +# ---------------------------------------------------------------------- + +upgrade 0 + +user root nodeidx=0 + +subtest upgrade_one_cast + +# Cast to PG_LSN. +statement error pgcode 0A000 pq: pg_lsn not supported until version 23.2 +SELECT 'a01f0/1aaa'::PG_LSN; + +# Cast to PG_LSN using the vectorized engine. +statement error pgcode 0A000 pq: pg_lsn not supported until version 23.2 +SELECT 'a01f0/1aaa'::PG_LSN FROM generate_series(1, 100) LIMIT 1; + +subtest upgrade_one_table + +# Table that references PG_LSN. +statement error pgcode 0A000 pq: pg_lsn not supported until version 23.2 +CREATE TABLE t (x PG_LSN); + +# Add a PG_LSN column. +statement error pgcode 0A000 pq: pg_lsn not supported until version 23.2 +ALTER TABLE xy ADD COLUMN curs PG_LSN; + +# Alter a column type to PG_LSN. +statement ok +SET enable_experimental_alter_column_type_general=true; + +statement error pgcode 0A000 pq: pg_lsn not supported until version 23.2 +ALTER TABLE xy ALTER COLUMN y TYPE PG_LSN; + +# Create a partial index that uses the PG_LSN type. +statement error pgcode 0A000 pq: pg_lsn not supported until version 23.2 +CREATE INDEX part ON xy (x) WHERE y::PG_LSN < 'a01f0/1aaa'; + +# Add a check constraint that uses the PG_LSN type. +statement error pgcode 0A000 pq: pg_lsn not supported until version 23.2 +ALTER TABLE xy ADD CONSTRAINT bar CHECK (y::PG_LSN < 'fffff100/100'); + +subtest upgrade_one_type + +# UDT that references PG_LSN. +statement error pgcode 0A000 pq: pg_lsn not supported until version 23.2 +CREATE TYPE typ AS (x INT, y PG_LSN); + +subtest upgrade_one_function + +# Function that returns PG_LSN. +statement error pgcode 0A000 pq: pg_lsn not supported until version 23.2 +CREATE OR REPLACE FUNCTION f() RETURNS PG_LSN AS $$ + SELECT 'a01f0/1aaa'; +$$ LANGUAGE SQL; + +# Function that takes PG_LSN argument. +statement error pgcode 0A000 pq: pg_lsn not supported until version 23.2 +CREATE OR REPLACE FUNCTION f(curs PG_LSN) RETURNS INT AS $$ + SELECT 0; +$$ LANGUAGE SQL; + +# Function that references PG_LSN internally. +statement error pgcode 0A000 pq: pg_lsn not supported until version 23.2 +CREATE OR REPLACE FUNCTION f() RETURNS INT AS $$ + SELECT 'a01f0/1aaa'::PG_LSN; + SELECT 0; +$$ LANGUAGE SQL; + +# Function that returns a composite type with PG_LSN component. +statement error pgcode 0A000 pq: pg_lsn not supported until version 23.2 +CREATE FUNCTION f() RETURNS RECORD AS $$ + SELECT (1, 'a01f0/1aaa'::PG_LSN, true); +$$ LANGUAGE SQL; + +statement error pgcode 0A000 pq: pg_lsn not supported until version 23.2 +CREATE FUNCTION f() RETURNS RECORD AS $$ + BEGIN + RETURN (1, 'a01f0/1aaa'::PG_LSN, true); + END +$$ LANGUAGE PLpgSQL; + +subtest end diff --git a/pkg/sql/logictest/testdata/logic_test/refcursor b/pkg/sql/logictest/testdata/logic_test/refcursor new file mode 100644 index 000000000000..1055f9976c11 --- /dev/null +++ b/pkg/sql/logictest/testdata/logic_test/refcursor @@ -0,0 +1,224 @@ +# LogicTest: !local-mixed-22.2-23.1 + +statement ok +CREATE TABLE xy (x INT, y INT); + +subtest cast + +# Cast to REFCURSOR. +query T +SELECT 'foo'::REFCURSOR; +---- +foo + +# Cast to REFCURSOR using the vectorized engine. +query T +SELECT 'foo'::REFCURSOR FROM generate_series(1, 100) LIMIT 1; +---- +foo + +subtest table + +# Table that references REFCURSOR. +statement ok +CREATE TABLE t (x REFCURSOR); + +# Add a REFCURSOR column. +statement ok +ALTER TABLE xy ADD COLUMN curs REFCURSOR; + +statement ok +INSERT INTO xy VALUES (1, 2, 'foo'); + +query IIT +SELECT * FROM xy; +---- +1 2 foo + +# Alter a column type to REFCURSOR. +statement ok +DROP TABLE IF EXISTS xy; +CREATE TABLE xy (x INT, y INT); +SET enable_experimental_alter_column_type_general=true; + +statement ok +ALTER TABLE xy ALTER COLUMN y TYPE REFCURSOR; + +statement ok +INSERT INTO xy VALUES (1, 'bar'); + +query IT +SELECT * FROM xy; +---- +1 bar + +statement ok +DROP TABLE IF EXISTS xy; +CREATE TABLE xy (x INT, y INT); +INSERT INTO xy VALUES (1, 2); +INSERT INTO xy VALUES (3, 4); + +# Create a partial index that uses the REFCURSOR type. +statement ok +CREATE INDEX part ON xy (x) WHERE y::REFCURSOR < '3'; + +query II +SELECT * FROM xy@part WHERE y::REFCURSOR < '3'; +---- +1 2 + +statement ok +DROP TABLE IF EXISTS xy; +CREATE TABLE xy (x INT, y INT); +INSERT INTO xy VALUES (1, 2); + +# Add a check constraint that uses the REFCURSOR type. +statement ok +ALTER TABLE xy ADD CONSTRAINT bar CHECK (y::REFCURSOR < 'baz'); + +query II +SELECT * FROM xy; +---- +1 2 + +subtest type + +# UDT that references REFCURSOR. +statement ok +CREATE TYPE typ AS (x INT, y REFCURSOR); + +query T +SELECT (100, 'bar')::typ; +---- +(100,bar) + +subtest function + +# Function that returns REFCURSOR. +statement ok +CREATE FUNCTION f() RETURNS REFCURSOR AS $$ + SELECT 'foo'; +$$ LANGUAGE SQL; + +query T +SELECT f(); +---- +foo + +statement ok +DROP FUNCTION f; + +statement ok +CREATE FUNCTION f() RETURNS REFCURSOR AS $$ + BEGIN + RETURN 'foo'; + END +$$ LANGUAGE PLpgSQL; + +query T +SELECT f(); +---- +foo + +statement ok +DROP FUNCTION f; + +# Function that takes REFCURSOR argument. +statement ok +CREATE FUNCTION f(curs REFCURSOR) RETURNS INT AS $$ + SELECT 0; +$$ LANGUAGE SQL; + +query I +SELECT f('foo'); +---- +0 + +statement ok +DROP FUNCTION f; + +statement ok +CREATE FUNCTION f(curs REFCURSOR) RETURNS INT AS $$ + BEGIN + RETURN 0; + END +$$ LANGUAGE PLpgSQL; + +query I +SELECT f('foo'); +---- +0 + +statement ok +DROP FUNCTION f; + +# Function that references REFCURSOR internally. +statement ok +CREATE FUNCTION f() RETURNS INT AS $$ + SELECT 'foo'::REFCURSOR; + SELECT 0; +$$ LANGUAGE SQL; + +query I +SELECT f(); +---- +0 + +statement ok +DROP FUNCTION f; + +statement ok +CREATE FUNCTION f() RETURNS INT AS $$ + BEGIN + SELECT 'foo'::REFCURSOR; + RETURN 0; + END +$$ LANGUAGE PLpgSQL; + +query I +SELECT f(); +---- +0 + +statement ok +DROP FUNCTION f; + +# Function that returns a composite type with REFCURSOR component. +statement ok +CREATE FUNCTION f() RETURNS typ AS $$ + SELECT (1, 'foo'); +$$ LANGUAGE SQL; + +query T +SELECT f(); +---- +(1,foo) + +statement ok +DROP FUNCTION f; + +statement ok +CREATE FUNCTION f() RETURNS typ AS $$ + BEGIN + RETURN (1, 'foo'); + END +$$ LANGUAGE PLpgSQL; + +query T +SELECT f(); +---- +(1,foo) + +subtest error + +# TODO(drewk): REFCURSOR should not support collation. +query T +SELECT 'foo'::REFCURSOR COLLATE en; +---- +foo + +# REFCURSOR does not have a width. +statement error pgcode 42601 syntax error +SELECT 'foo'::REFCURSOR(2); + +subtest end diff --git a/pkg/sql/logictest/tests/cockroach-go-testserver-upgrade-to-master/BUILD.bazel b/pkg/sql/logictest/tests/cockroach-go-testserver-upgrade-to-master/BUILD.bazel index cee2384240f3..15cc14daa5ae 100644 --- a/pkg/sql/logictest/tests/cockroach-go-testserver-upgrade-to-master/BUILD.bazel +++ b/pkg/sql/logictest/tests/cockroach-go-testserver-upgrade-to-master/BUILD.bazel @@ -15,7 +15,7 @@ go_test( "//pkg/sql/logictest:testdata", # keep ], exec_properties = {"Pool": "large"}, - shard_count = 12, + shard_count = 14, tags = [ "cpu:2", ], diff --git a/pkg/sql/logictest/tests/cockroach-go-testserver-upgrade-to-master/generated_test.go b/pkg/sql/logictest/tests/cockroach-go-testserver-upgrade-to-master/generated_test.go index 73514f4ee4bd..418bd7186b1d 100644 --- a/pkg/sql/logictest/tests/cockroach-go-testserver-upgrade-to-master/generated_test.go +++ b/pkg/sql/logictest/tests/cockroach-go-testserver-upgrade-to-master/generated_test.go @@ -127,6 +127,13 @@ func TestLogic_mixed_version_range_tombstones( runLogicTest(t, "mixed_version_range_tombstones") } +func TestLogic_mixed_version_refcursor( + t *testing.T, +) { + defer leaktest.AfterTest(t)() + runLogicTest(t, "mixed_version_refcursor") +} + func TestLogic_mixed_version_role_members_user_ids( t *testing.T, ) { @@ -161,3 +168,10 @@ func TestLogic_mixed_version_upgrade_repair_descriptors( defer leaktest.AfterTest(t)() runLogicTest(t, "mixed_version_upgrade_repair_descriptors") } + +func TestLogic_pg_lsn_mixed( + t *testing.T, +) { + defer leaktest.AfterTest(t)() + runLogicTest(t, "pg_lsn_mixed") +} diff --git a/pkg/sql/logictest/tests/fakedist-disk/generated_test.go b/pkg/sql/logictest/tests/fakedist-disk/generated_test.go index d1b48dd4fcea..0b7814af0135 100644 --- a/pkg/sql/logictest/tests/fakedist-disk/generated_test.go +++ b/pkg/sql/logictest/tests/fakedist-disk/generated_test.go @@ -1471,6 +1471,13 @@ func TestLogic_redact_descriptor( runLogicTest(t, "redact_descriptor") } +func TestLogic_refcursor( + t *testing.T, +) { + defer leaktest.AfterTest(t)() + runLogicTest(t, "refcursor") +} + func TestLogic_rename_atomic( t *testing.T, ) { diff --git a/pkg/sql/logictest/tests/fakedist-vec-off/generated_test.go b/pkg/sql/logictest/tests/fakedist-vec-off/generated_test.go index 573d8fa23e18..52c4af1a77d2 100644 --- a/pkg/sql/logictest/tests/fakedist-vec-off/generated_test.go +++ b/pkg/sql/logictest/tests/fakedist-vec-off/generated_test.go @@ -1471,6 +1471,13 @@ func TestLogic_redact_descriptor( runLogicTest(t, "redact_descriptor") } +func TestLogic_refcursor( + t *testing.T, +) { + defer leaktest.AfterTest(t)() + runLogicTest(t, "refcursor") +} + func TestLogic_rename_atomic( t *testing.T, ) { diff --git a/pkg/sql/logictest/tests/fakedist/generated_test.go b/pkg/sql/logictest/tests/fakedist/generated_test.go index e2b17f078ae9..079d07c05655 100644 --- a/pkg/sql/logictest/tests/fakedist/generated_test.go +++ b/pkg/sql/logictest/tests/fakedist/generated_test.go @@ -1485,6 +1485,13 @@ func TestLogic_redact_descriptor( runLogicTest(t, "redact_descriptor") } +func TestLogic_refcursor( + t *testing.T, +) { + defer leaktest.AfterTest(t)() + runLogicTest(t, "refcursor") +} + func TestLogic_rename_atomic( t *testing.T, ) { diff --git a/pkg/sql/logictest/tests/local-legacy-schema-changer/generated_test.go b/pkg/sql/logictest/tests/local-legacy-schema-changer/generated_test.go index 96104843f73b..078041c8d682 100644 --- a/pkg/sql/logictest/tests/local-legacy-schema-changer/generated_test.go +++ b/pkg/sql/logictest/tests/local-legacy-schema-changer/generated_test.go @@ -1457,6 +1457,13 @@ func TestLogic_redact_descriptor( runLogicTest(t, "redact_descriptor") } +func TestLogic_refcursor( + t *testing.T, +) { + defer leaktest.AfterTest(t)() + runLogicTest(t, "refcursor") +} + func TestLogic_rename_atomic( t *testing.T, ) { diff --git a/pkg/sql/logictest/tests/local-mixed-22.2-23.1/generated_test.go b/pkg/sql/logictest/tests/local-mixed-22.2-23.1/generated_test.go index 1e6019b09994..998b4080a2b4 100644 --- a/pkg/sql/logictest/tests/local-mixed-22.2-23.1/generated_test.go +++ b/pkg/sql/logictest/tests/local-mixed-22.2-23.1/generated_test.go @@ -1317,13 +1317,6 @@ func TestLogic_pg_extension( runLogicTest(t, "pg_extension") } -func TestLogic_pg_lsn_mixed( - t *testing.T, -) { - defer leaktest.AfterTest(t)() - runLogicTest(t, "pg_lsn_mixed") -} - func TestLogic_pgcrypto_builtins( t *testing.T, ) { diff --git a/pkg/sql/logictest/tests/local-vec-off/generated_test.go b/pkg/sql/logictest/tests/local-vec-off/generated_test.go index efe4223a67f4..c17a53a77b70 100644 --- a/pkg/sql/logictest/tests/local-vec-off/generated_test.go +++ b/pkg/sql/logictest/tests/local-vec-off/generated_test.go @@ -1485,6 +1485,13 @@ func TestLogic_redact_descriptor( runLogicTest(t, "redact_descriptor") } +func TestLogic_refcursor( + t *testing.T, +) { + defer leaktest.AfterTest(t)() + runLogicTest(t, "refcursor") +} + func TestLogic_rename_atomic( t *testing.T, ) { diff --git a/pkg/sql/logictest/tests/local/generated_test.go b/pkg/sql/logictest/tests/local/generated_test.go index 83ded7f08663..f7ab7f71d149 100644 --- a/pkg/sql/logictest/tests/local/generated_test.go +++ b/pkg/sql/logictest/tests/local/generated_test.go @@ -1625,6 +1625,13 @@ func TestLogic_redact_descriptor( runLogicTest(t, "redact_descriptor") } +func TestLogic_refcursor( + t *testing.T, +) { + defer leaktest.AfterTest(t)() + runLogicTest(t, "refcursor") +} + func TestLogic_rename_atomic( t *testing.T, ) { diff --git a/pkg/sql/opt/optbuilder/create_function.go b/pkg/sql/opt/optbuilder/create_function.go index de80d5cc743f..5238330f8078 100644 --- a/pkg/sql/opt/optbuilder/create_function.go +++ b/pkg/sql/opt/optbuilder/create_function.go @@ -11,6 +11,7 @@ package optbuilder import ( + "context" "fmt" "github.com/cockroachdb/cockroach/pkg/sql/catalog/descpb" @@ -146,6 +147,8 @@ func (b *Builder) buildCreateFunction(cf *tree.CreateRoutine, inScope *scope) (o if err != nil { panic(err) } + // The parameter type must be supported by the current cluster version. + checkUnsupportedType(b.ctx, b.semaCtx, typ) if types.IsRecordType(typ) { if language == tree.RoutineLangSQL { panic(pgerror.Newf(pgcode.InvalidFunctionDefinition, @@ -258,7 +261,7 @@ func (b *Builder) buildCreateFunction(cf *tree.CreateRoutine, inScope *scope) (o // TODO(mgartner): stmtScope.cols does not describe the result // columns of the statement. We should use physical.Presentation // instead. - err = validateReturnType(funcReturnType, stmtScope.cols) + err = validateReturnType(b.ctx, b.semaCtx, funcReturnType, stmtScope.cols) if err != nil { panic(err) } @@ -301,7 +304,15 @@ func formatFuncBodyStmt(fmtCtx *tree.FmtCtx, ast tree.NodeFormatter, newLine boo fmtCtx.WriteString(";") } -func validateReturnType(expected *types.T, cols []scopeColumn) error { +func validateReturnType( + ctx context.Context, semaCtx *tree.SemaContext, expected *types.T, cols []scopeColumn, +) error { + // The return type must be supported by the current cluster version. + checkUnsupportedType(ctx, semaCtx, expected) + for i := range cols { + checkUnsupportedType(ctx, semaCtx, cols[i].typ) + } + // If return type is void, any column types are valid. if expected.Equivalent(types.Void) { return nil @@ -406,3 +417,9 @@ func checkStmtVolatility( } } } + +func checkUnsupportedType(ctx context.Context, semaCtx *tree.SemaContext, typ *types.T) { + if err := tree.CheckUnsupportedType(ctx, semaCtx, typ); err != nil { + panic(err) + } +} diff --git a/pkg/sql/pgwire/pgwirebase/encoding.go b/pkg/sql/pgwire/pgwirebase/encoding.go index 7ed338cdbcf6..07dd147c2f1d 100644 --- a/pkg/sql/pgwire/pgwirebase/encoding.go +++ b/pkg/sql/pgwire/pgwirebase/encoding.go @@ -817,7 +817,7 @@ func DecodeDatum( return tree.NewDEnum(e), nil } switch id { - case oid.T_text, oid.T_varchar, oid.T_unknown: + case oid.T_text, oid.T_varchar, oid.T_refcursor, oid.T_unknown: if err := validateStringBytes(b); err != nil { return nil, err } diff --git a/pkg/sql/planner.go b/pkg/sql/planner.go index 3b9c2956a150..4e2560434bc0 100644 --- a/pkg/sql/planner.go +++ b/pkg/sql/planner.go @@ -404,6 +404,7 @@ func newInternalPlanner( p.semaCtx.NameResolver = p p.semaCtx.DateStyle = sd.GetDateStyle() p.semaCtx.IntervalStyle = sd.GetIntervalStyle() + p.semaCtx.UnsupportedTypeChecker = eval.NewUnsupportedTypeChecker(execCfg.Settings.Version) plannerMon := mon.NewMonitor(redact.Sprintf("internal-planner.%s.%s", user, opName), mon.MemoryResource, @@ -903,6 +904,7 @@ func (p *planner) resetPlanner( p.semaCtx.NameResolver = p p.semaCtx.DateStyle = sd.GetDateStyle() p.semaCtx.IntervalStyle = sd.GetIntervalStyle() + p.semaCtx.UnsupportedTypeChecker = eval.NewUnsupportedTypeChecker(p.execCfg.Settings.Version) p.autoCommit = false diff --git a/pkg/sql/schemachanger/scbuild/tree_context_builder.go b/pkg/sql/schemachanger/scbuild/tree_context_builder.go index e5ee28360a0c..921552fc381a 100644 --- a/pkg/sql/schemachanger/scbuild/tree_context_builder.go +++ b/pkg/sql/schemachanger/scbuild/tree_context_builder.go @@ -36,6 +36,7 @@ func newSemaCtx(d Dependencies) *tree.SemaContext { semaCtx.NameResolver = d.CatalogReader() semaCtx.DateStyle = d.SessionData().GetDateStyle() semaCtx.IntervalStyle = d.SessionData().GetIntervalStyle() + semaCtx.UnsupportedTypeChecker = eval.NewUnsupportedTypeChecker(d.ClusterSettings().Version) return &semaCtx } diff --git a/pkg/sql/sem/builtins/fixed_oids.go b/pkg/sql/sem/builtins/fixed_oids.go index e94bb414177c..25654ead9509 100644 --- a/pkg/sql/sem/builtins/fixed_oids.go +++ b/pkg/sql/sem/builtins/fixed_oids.go @@ -2466,6 +2466,35 @@ var builtinOidsArray = []string{ 2495: `crdb_internal.plpgsql_gen_cursor_name(name: string) -> string`, 2496: `crdb_internal.plpgsql_close(name: string) -> int`, 2497: `crdb_internal.plpgsql_fetch(name: string, direction: int, count: int, resultTypes: anyelement) -> anyelement`, + 2498: `refcursorin(input: anyelement) -> refcursor`, + 2499: `refcursorout(refcursor: refcursor) -> bytes`, + 2500: `refcursorsend(refcursor: refcursor) -> bytes`, + 2501: `refcursorrecv(input: anyelement) -> refcursor`, + 2502: `refcursor(time: time) -> refcursor`, + 2503: `refcursor(tsvector: tsvector) -> refcursor`, + 2504: `refcursor(date: date) -> refcursor`, + 2505: `refcursor(float: float) -> refcursor`, + 2506: `refcursor(decimal: decimal) -> refcursor`, + 2507: `refcursor(timestamp: timestamp) -> refcursor`, + 2508: `refcursor(void: void) -> refcursor`, + 2509: `refcursor(bool: bool) -> refcursor`, + 2510: `refcursor(bytes: bytes) -> refcursor`, + 2511: `refcursor(jsonb: jsonb) -> refcursor`, + 2512: `refcursor(timetz: timetz) -> refcursor`, + 2513: `refcursor(tsquery: tsquery) -> refcursor`, + 2514: `refcursor(bit: bit) -> refcursor`, + 2515: `refcursor(interval: interval) -> refcursor`, + 2516: `refcursor(string: string) -> refcursor`, + 2517: `refcursor(pg_lsn: pg_lsn) -> refcursor`, + 2518: `refcursor(int: int) -> refcursor`, + 2519: `refcursor(uuid: uuid) -> refcursor`, + 2520: `refcursor(inet: inet) -> refcursor`, + 2521: `refcursor(timestamptz: timestamptz) -> refcursor`, + 2522: `refcursor(box2d: box2d) -> refcursor`, + 2523: `refcursor(geometry: geometry) -> refcursor`, + 2524: `refcursor(oid: oid) -> refcursor`, + 2525: `refcursor(tuple: tuple) -> refcursor`, + 2526: `refcursor(geography: geography) -> refcursor`, } var builtinOidsBySignature map[string]oid.Oid diff --git a/pkg/sql/sem/cast/cast_map.go b/pkg/sql/sem/cast/cast_map.go index 859b8e916b85..b31b86a513e4 100644 --- a/pkg/sql/sem/cast/cast_map.go +++ b/pkg/sql/sem/cast/cast_map.go @@ -36,11 +36,12 @@ var castMap = map[oid.Oid]map[oid.Oid]Cast{ oid.T_int8: {MaxContext: ContextExplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable}, oid.T_varbit: {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable}, // Automatic I/O conversions to string types. - oid.T_bpchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, - oid.T_char: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, - oid.T_name: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, - oid.T_text: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, - oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_bpchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_char: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_name: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_text: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_refcursor: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, }, oid.T_bool: { oid.T_bpchar: {MaxContext: ContextAssignment, origin: ContextOriginPgCast, Volatility: volatility.Immutable}, @@ -53,24 +54,27 @@ var castMap = map[oid.Oid]map[oid.Oid]Cast{ oid.T_text: {MaxContext: ContextAssignment, origin: ContextOriginPgCast, Volatility: volatility.Immutable}, oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginPgCast, Volatility: volatility.Immutable}, // Automatic I/O conversions to string types. - oid.T_char: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, - oid.T_name: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_char: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_name: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_refcursor: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, }, oidext.T_box2d: { oidext.T_geometry: {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable}, // Automatic I/O conversions to string types. - oid.T_bpchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, - oid.T_char: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, - oid.T_name: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, - oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, - oid.T_text: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_bpchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_char: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_name: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_text: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_refcursor: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, }, oid.T_pg_lsn: { - oid.T_bpchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, - oid.T_char: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, - oid.T_name: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, - oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, - oid.T_text: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_bpchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_char: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_name: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_text: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_refcursor: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, }, oid.T_bpchar: { oid.T_bpchar: {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable}, @@ -78,6 +82,8 @@ var castMap = map[oid.Oid]map[oid.Oid]Cast{ oid.T_name: {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable}, oid.T_text: {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable}, oid.T_varchar: {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable}, + // Automatic I/O conversions to string types. + oid.T_refcursor: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, // Automatic I/O conversions from bpchar to other types. oid.T_bit: {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, oid.T_bool: {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, @@ -151,11 +157,12 @@ var castMap = map[oid.Oid]map[oid.Oid]Cast{ // Automatic I/O conversions to string types. // Casts from BYTEA to string types are stable, since they depend on // the bytea_output session variable. - oid.T_bpchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, - oid.T_char: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, - oid.T_name: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, - oid.T_text: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, - oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, + oid.T_bpchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, + oid.T_char: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, + oid.T_name: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, + oid.T_text: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, + oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, + oid.T_refcursor: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, }, oid.T_char: { oid.T_bpchar: {MaxContext: ContextAssignment, origin: ContextOriginPgCast, Volatility: volatility.Immutable}, @@ -163,7 +170,8 @@ var castMap = map[oid.Oid]map[oid.Oid]Cast{ oid.T_text: {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable}, oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginPgCast, Volatility: volatility.Immutable}, // Automatic I/O conversions to string types. - oid.T_name: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_name: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_refcursor: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, // Automatic I/O conversions from "char" to other types. oid.T_bit: {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, oid.T_bool: {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, @@ -274,6 +282,13 @@ var castMap = map[oid.Oid]map[oid.Oid]Cast{ VolatilityHint: "DATE to VARCHAR casts are dependent on DateStyle; consider " + "using to_char(date) instead.", }, + oid.T_refcursor: { + MaxContext: ContextAssignment, + origin: ContextOriginAutomaticIOConversion, + Volatility: volatility.Stable, + VolatilityHint: "DATE to REFCURSOR casts are dependent on DateStyle; consider " + + "using to_char(date) instead.", + }, }, oid.T_float4: { oid.T_bool: {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable}, @@ -286,11 +301,12 @@ var castMap = map[oid.Oid]map[oid.Oid]Cast{ // Automatic I/O conversions to string types. // Casts from FLOAT4 to string types are stable, since they depend on the // extra_float_digits session variable. - oid.T_bpchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, - oid.T_char: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, - oid.T_name: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, - oid.T_text: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, - oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, + oid.T_bpchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, + oid.T_char: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, + oid.T_name: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, + oid.T_text: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, + oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, + oid.T_refcursor: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, }, oid.T_float8: { oid.T_bool: {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable}, @@ -303,11 +319,12 @@ var castMap = map[oid.Oid]map[oid.Oid]Cast{ // Automatic I/O conversions to string types. // Casts from FLOAT8 to string types are stable, since they depend on the // extra_float_digits session variable. - oid.T_bpchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, - oid.T_char: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, - oid.T_name: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, - oid.T_text: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, - oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, + oid.T_bpchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, + oid.T_char: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, + oid.T_name: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, + oid.T_text: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, + oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, + oid.T_refcursor: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, }, oidext.T_geography: { oid.T_bytea: {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable}, @@ -315,11 +332,12 @@ var castMap = map[oid.Oid]map[oid.Oid]Cast{ oidext.T_geometry: {MaxContext: ContextExplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable}, oid.T_jsonb: {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable}, // Automatic I/O conversions to string types. - oid.T_bpchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, - oid.T_char: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, - oid.T_name: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, - oid.T_text: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, - oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_bpchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_char: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_name: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_text: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_refcursor: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, }, oidext.T_geometry: { oidext.T_box2d: {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable}, @@ -329,18 +347,20 @@ var castMap = map[oid.Oid]map[oid.Oid]Cast{ oid.T_jsonb: {MaxContext: ContextExplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable}, oid.T_text: {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable}, // Automatic I/O conversions to string types. - oid.T_bpchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, - oid.T_char: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, - oid.T_name: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, - oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_bpchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_char: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_name: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_refcursor: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, }, oid.T_inet: { oid.T_bpchar: {MaxContext: ContextAssignment, origin: ContextOriginPgCast, Volatility: volatility.Immutable}, oid.T_text: {MaxContext: ContextAssignment, origin: ContextOriginPgCast, Volatility: volatility.Immutable}, oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginPgCast, Volatility: volatility.Immutable}, // Automatic I/O conversions to string types. - oid.T_char: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, - oid.T_name: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_char: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_name: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_refcursor: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, }, oid.T_int2: { oid.T_bool: {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable}, @@ -361,11 +381,12 @@ var castMap = map[oid.Oid]map[oid.Oid]Cast{ oid.T_timestamp: {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable}, oid.T_timestamptz: {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable}, // Automatic I/O conversions to string types. - oid.T_bpchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, - oid.T_char: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, - oid.T_name: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, - oid.T_text: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, - oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_bpchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_char: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_name: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_text: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_refcursor: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, }, oid.T_int4: { oid.T_bit: {MaxContext: ContextExplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable}, @@ -388,10 +409,11 @@ var castMap = map[oid.Oid]map[oid.Oid]Cast{ oid.T_timestamp: {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable}, oid.T_timestamptz: {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable}, // Automatic I/O conversions to string types. - oid.T_bpchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, - oid.T_name: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, - oid.T_text: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, - oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_bpchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_name: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_text: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_refcursor: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, }, oid.T_int8: { oid.T_bit: {MaxContext: ContextExplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable}, @@ -413,11 +435,12 @@ var castMap = map[oid.Oid]map[oid.Oid]Cast{ oid.T_timestamp: {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable}, oid.T_timestamptz: {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable}, // Automatic I/O conversions to string types. - oid.T_bpchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, - oid.T_char: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, - oid.T_name: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, - oid.T_text: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, - oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_bpchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_char: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_name: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_text: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_refcursor: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, }, oid.T_interval: { oid.T_float4: {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable}, @@ -459,6 +482,12 @@ var castMap = map[oid.Oid]map[oid.Oid]Cast{ Volatility: volatility.Stable, VolatilityHint: "INTERVAL to VARCHAR casts depend on IntervalStyle; consider using to_char(interval)", }, + oid.T_refcursor: { + MaxContext: ContextAssignment, + origin: ContextOriginAutomaticIOConversion, + Volatility: volatility.Stable, + VolatilityHint: "INTERVAL to REFCURSOR casts depend on IntervalStyle; consider using to_char(interval)", + }, }, oid.T_jsonb: { oid.T_bool: {MaxContext: ContextExplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable}, @@ -471,18 +500,20 @@ var castMap = map[oid.Oid]map[oid.Oid]Cast{ oid.T_int8: {MaxContext: ContextExplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable}, oid.T_numeric: {MaxContext: ContextExplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable}, // Automatic I/O conversions to string types. - oid.T_bpchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, - oid.T_char: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, - oid.T_name: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, - oid.T_text: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, - oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_bpchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_char: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_name: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_text: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_refcursor: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, }, oid.T_name: { oid.T_bpchar: {MaxContext: ContextAssignment, origin: ContextOriginPgCast, Volatility: volatility.Immutable}, oid.T_text: {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Leakproof}, oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginPgCast, Volatility: volatility.Immutable}, // Automatic I/O conversions to string types. - oid.T_char: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_char: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_refcursor: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, // Automatic I/O conversions from NAME to other types. oid.T_bit: {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, oid.T_bool: {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, @@ -559,11 +590,12 @@ var castMap = map[oid.Oid]map[oid.Oid]Cast{ oid.T_interval: {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable}, oid.T_numeric: {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable}, // Automatic I/O conversions to string types. - oid.T_bpchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, - oid.T_char: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, - oid.T_name: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, - oid.T_text: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, - oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_bpchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_char: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_name: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_text: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_refcursor: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, }, oid.T_oid: { // TODO(mgartner): Casts to INT2 should not be allowed. @@ -577,19 +609,97 @@ var castMap = map[oid.Oid]map[oid.Oid]Cast{ oid.T_regrole: {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable}, oid.T_regtype: {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable}, // Automatic I/O conversions to string types. + oid.T_bpchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_char: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_name: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_text: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_refcursor: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + }, + oid.T_record: { + // Automatic I/O conversions to string types. + oid.T_bpchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, + oid.T_char: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, + oid.T_name: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, + oid.T_text: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, + oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, + oid.T_refcursor: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, + }, + oid.T_refcursor: { + // The REFCURSOR data type has no casts in the pg_cast table; all of its + // casts are the I/O casts for string types. + // + // Automatic I/O conversions to string types. oid.T_bpchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, oid.T_char: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, - oid.T_name: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_name: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Leakproof}, oid.T_text: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, - }, - oid.T_record: { - // Automatic I/O conversions to string types. - oid.T_bpchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, - oid.T_char: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, - oid.T_name: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, - oid.T_text: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, - oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, + // Automatic I/O conversions from REFCURSOR to other types. + oid.T_bit: {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_bool: {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oidext.T_box2d: {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_pg_lsn: {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_bytea: {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_date: { + MaxContext: ContextExplicit, + origin: ContextOriginAutomaticIOConversion, + Volatility: volatility.Stable, + VolatilityHint: "REFCURSOR to DATE casts depend on session DateStyle; use parse_date(string) instead", + }, + oid.T_float4: {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_float8: {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oidext.T_geography: {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oidext.T_geometry: {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_inet: {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_int2: {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_int4: {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_int8: {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_interval: { + MaxContext: ContextExplicit, + origin: ContextOriginAutomaticIOConversion, + Volatility: volatility.Stable, + VolatilityHint: "REFCURSOR to INTERVAL casts depend on session IntervalStyle; use parse_interval(string) instead", + }, + oid.T_jsonb: {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_numeric: {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_oid: {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_record: {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, + oid.T_regclass: {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, + oid.T_regnamespace: {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, + oid.T_regproc: {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, + oid.T_regprocedure: {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, + oid.T_regrole: {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, + oid.T_regtype: {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, + oid.T_time: { + MaxContext: ContextExplicit, + origin: ContextOriginAutomaticIOConversion, + Volatility: volatility.Stable, + VolatilityHint: "STRING to TIME casts depend on session DateStyle; use parse_time(string) instead", + }, + oid.T_timestamp: { + MaxContext: ContextExplicit, + origin: ContextOriginAutomaticIOConversion, + Volatility: volatility.Stable, + VolatilityHint: "STRING to TIMESTAMP casts are context-dependent because of relative timestamp strings " + + "like 'now' and session settings such as DateStyle; use parse_timestamp(string) instead.", + }, + oid.T_timestamptz: { + MaxContext: ContextExplicit, + origin: ContextOriginAutomaticIOConversion, + Volatility: volatility.Stable, + }, + oid.T_timetz: { + MaxContext: ContextExplicit, + origin: ContextOriginAutomaticIOConversion, + Volatility: volatility.Stable, + VolatilityHint: "STRING to TIMETZ casts depend on session DateStyle; use parse_timetz(string) instead", + }, + oid.T_tsquery: {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_tsvector: {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_uuid: {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_varbit: {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_void: {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, }, oid.T_regclass: { // TODO(mgartner): Casts to INT2 should not be allowed. @@ -603,11 +713,12 @@ var castMap = map[oid.Oid]map[oid.Oid]Cast{ oid.T_regrole: {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Stable}, oid.T_regtype: {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Stable}, // Automatic I/O conversions to string types. - oid.T_bpchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, - oid.T_char: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, - oid.T_name: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, - oid.T_text: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, - oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, + oid.T_bpchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, + oid.T_char: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, + oid.T_name: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, + oid.T_text: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, + oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, + oid.T_refcursor: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, }, oid.T_regnamespace: { // TODO(mgartner): Casts to INT2 should not be allowed. @@ -621,11 +732,12 @@ var castMap = map[oid.Oid]map[oid.Oid]Cast{ oid.T_regrole: {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Stable}, oid.T_regtype: {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Stable}, // Automatic I/O conversions to string types. - oid.T_bpchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, - oid.T_char: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, - oid.T_name: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, - oid.T_text: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, - oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, + oid.T_bpchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, + oid.T_char: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, + oid.T_name: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, + oid.T_text: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, + oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, + oid.T_refcursor: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, }, oid.T_regproc: { // TODO(mgartner): Casts to INT2 should not be allowed. @@ -639,11 +751,12 @@ var castMap = map[oid.Oid]map[oid.Oid]Cast{ oid.T_regrole: {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Stable}, oid.T_regtype: {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Stable}, // Automatic I/O conversions to string types. - oid.T_bpchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, - oid.T_char: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, - oid.T_name: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, - oid.T_text: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, - oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, + oid.T_bpchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, + oid.T_char: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, + oid.T_name: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, + oid.T_text: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, + oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, + oid.T_refcursor: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, }, oid.T_regprocedure: { // TODO(mgartner): Casts to INT2 should not be allowed. @@ -657,11 +770,12 @@ var castMap = map[oid.Oid]map[oid.Oid]Cast{ oid.T_regrole: {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Stable}, oid.T_regtype: {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Stable}, // Automatic I/O conversions to string types. - oid.T_bpchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, - oid.T_char: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, - oid.T_name: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, - oid.T_text: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, - oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, + oid.T_bpchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, + oid.T_char: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, + oid.T_name: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, + oid.T_text: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, + oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, + oid.T_refcursor: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, }, oid.T_regrole: { // TODO(mgartner): Casts to INT2 should not be allowed. @@ -675,11 +789,12 @@ var castMap = map[oid.Oid]map[oid.Oid]Cast{ oid.T_regprocedure: {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Stable}, oid.T_regtype: {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Stable}, // Automatic I/O conversions to string types. - oid.T_bpchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, - oid.T_char: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, - oid.T_name: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, - oid.T_text: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, - oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, + oid.T_bpchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, + oid.T_char: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, + oid.T_name: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, + oid.T_text: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, + oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, + oid.T_refcursor: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, }, oid.T_regtype: { // TODO(mgartner): Casts to INT2 should not be allowed. @@ -693,11 +808,12 @@ var castMap = map[oid.Oid]map[oid.Oid]Cast{ oid.T_regprocedure: {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Stable}, oid.T_regrole: {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Stable}, // Automatic I/O conversions to string types. - oid.T_bpchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, - oid.T_char: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, - oid.T_name: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, - oid.T_text: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, - oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, + oid.T_bpchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, + oid.T_char: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, + oid.T_name: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, + oid.T_text: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, + oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, + oid.T_refcursor: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Stable}, }, oid.T_text: { oid.T_bpchar: {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable}, @@ -718,6 +834,8 @@ var castMap = map[oid.Oid]map[oid.Oid]Cast{ // then the TEXT OID, and we can remove this entry. oid.T_text: {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable}, oid.T_varchar: {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable}, + // Automatic I/O conversions to string types. + oid.T_refcursor: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, // Automatic I/O conversions from TEXT to other types. oid.T_bit: {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, oid.T_bool: {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, @@ -787,11 +905,12 @@ var castMap = map[oid.Oid]map[oid.Oid]Cast{ oid.T_time: {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable}, oid.T_timetz: {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Stable}, // Automatic I/O conversions to string types. - oid.T_bpchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, - oid.T_char: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, - oid.T_name: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, - oid.T_text: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, - oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_bpchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_char: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_name: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_text: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_refcursor: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, }, oid.T_timestamp: { oid.T_date: {MaxContext: ContextAssignment, origin: ContextOriginPgCast, Volatility: volatility.Immutable}, @@ -840,6 +959,13 @@ var castMap = map[oid.Oid]map[oid.Oid]Cast{ VolatilityHint: "TIMESTAMP to VARCHAR casts are dependent on DateStyle; consider " + "using to_char(timestamp) instead.", }, + oid.T_refcursor: { + MaxContext: ContextAssignment, + origin: ContextOriginAutomaticIOConversion, + Volatility: volatility.Stable, + VolatilityHint: "TIMESTAMP to REFCURSOR casts are dependent on DateStyle; consider " + + "using to_char(timestamp) instead.", + }, }, oid.T_timestamptz: { oid.T_date: {MaxContext: ContextAssignment, origin: ContextOriginPgCast, Volatility: volatility.Stable}, @@ -894,41 +1020,52 @@ var castMap = map[oid.Oid]map[oid.Oid]Cast{ VolatilityHint: "TIMESTAMPTZ to VARCHAR casts depend on the current timezone; consider " + "using to_char(t AT TIME ZONE 'UTC') instead.", }, + oid.T_refcursor: { + MaxContext: ContextAssignment, + origin: ContextOriginAutomaticIOConversion, + Volatility: volatility.Stable, + VolatilityHint: "TIMESTAMPTZ to REFCURSOR casts depend on the current timezone; consider " + + "using to_char(t AT TIME ZONE 'UTC') instead.", + }, }, oid.T_timetz: { oid.T_time: {MaxContext: ContextAssignment, origin: ContextOriginPgCast, Volatility: volatility.Immutable}, oid.T_timetz: {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable}, // Automatic I/O conversions to string types. - oid.T_bpchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, - oid.T_char: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, - oid.T_name: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, - oid.T_text: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, - oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_bpchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_char: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_name: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_text: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_refcursor: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, }, oid.T_tsvector: { // Automatic I/O conversions to string types. - oid.T_bpchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, - oid.T_char: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, - oid.T_name: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, - oid.T_text: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, - oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_bpchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_char: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_name: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_text: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_refcursor: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, }, oid.T_tsquery: { // Automatic I/O conversions to string types. - oid.T_bpchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, - oid.T_char: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, - oid.T_name: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, - oid.T_text: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, - oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_bpchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_char: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_name: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_text: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_refcursor: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, }, oid.T_uuid: { oid.T_bytea: {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable}, // Automatic I/O conversions to string types. - oid.T_bpchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, - oid.T_char: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, - oid.T_name: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, - oid.T_text: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, - oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_bpchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_char: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_name: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_text: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_refcursor: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, }, oid.T_varbit: { oid.T_bit: {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable}, @@ -937,11 +1074,12 @@ var castMap = map[oid.Oid]map[oid.Oid]Cast{ oid.T_int8: {MaxContext: ContextExplicit, origin: ContextOriginLegacyConversion, Volatility: volatility.Immutable}, oid.T_varbit: {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable}, // Automatic I/O conversions to string types. - oid.T_bpchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, - oid.T_char: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, - oid.T_name: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, - oid.T_text: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, - oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_bpchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_char: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_name: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_text: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_refcursor: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, }, oid.T_varchar: { oid.T_bpchar: {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable}, @@ -950,6 +1088,8 @@ var castMap = map[oid.Oid]map[oid.Oid]Cast{ oid.T_regclass: {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Stable}, oid.T_text: {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable}, oid.T_varchar: {MaxContext: ContextImplicit, origin: ContextOriginPgCast, Volatility: volatility.Immutable}, + // Automatic I/O conversions to string types. + oid.T_refcursor: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, // Automatic I/O conversions from VARCHAR to other types. oid.T_bit: {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, oid.T_bool: {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, @@ -1016,11 +1156,12 @@ var castMap = map[oid.Oid]map[oid.Oid]Cast{ oid.T_void: {MaxContext: ContextExplicit, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, }, oid.T_void: { - oid.T_bpchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, - oid.T_char: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, - oid.T_name: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, - oid.T_text: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, - oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_bpchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_char: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_name: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_text: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_varchar: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, + oid.T_refcursor: {MaxContext: ContextAssignment, origin: ContextOriginAutomaticIOConversion, Volatility: volatility.Immutable}, }, } @@ -1032,6 +1173,7 @@ func init() { oid.T_char, oid.T_varchar, oid.T_text, + oid.T_refcursor, } isStringType := func(o oid.Oid) bool { for _, strOid := range stringTypes { diff --git a/pkg/sql/sem/eval/BUILD.bazel b/pkg/sql/sem/eval/BUILD.bazel index 0f597f8de4b4..67b3d2883676 100644 --- a/pkg/sql/sem/eval/BUILD.bazel +++ b/pkg/sql/sem/eval/BUILD.bazel @@ -29,6 +29,7 @@ go_library( "testing_knobs.go", "tuple.go", "unary_op.go", + "unsupported_types.go", "window_funcs.go", "window_funcs_util.go", ], diff --git a/pkg/sql/sem/eval/cast.go b/pkg/sql/sem/eval/cast.go index 593af46a8bdc..276e3027ad03 100644 --- a/pkg/sql/sem/eval/cast.go +++ b/pkg/sql/sem/eval/cast.go @@ -416,6 +416,13 @@ func performCastWithoutPrecisionTruncation( case types.StringFamily, types.CollatedStringFamily: var s string typ := t + if typ.Oid() == oid.T_refcursor { + if !evalCtx.Settings.Version.IsActive(ctx, clusterversion.V23_2) { + return nil, pgerror.Newf(pgcode.FeatureNotSupported, + "refcursor not supported until version 23.2", + ) + } + } switch t := d.(type) { case *tree.DBitArray: s = t.BitArray.String() diff --git a/pkg/sql/sem/eval/unsupported_types.go b/pkg/sql/sem/eval/unsupported_types.go new file mode 100644 index 000000000000..eb123d5bfc83 --- /dev/null +++ b/pkg/sql/sem/eval/unsupported_types.go @@ -0,0 +1,50 @@ +// Copyright 2023 The Cockroach Authors. +// +// Use of this software is governed by the Business Source License +// included in the file licenses/BSL.txt. +// +// As of the Change Date specified in that file, in accordance with +// the Business Source License, use of this software will be governed +// by the Apache License, Version 2.0, included in the file +// licenses/APL.txt. + +package eval + +import ( + "context" + + "github.com/cockroachdb/cockroach/pkg/clusterversion" + "github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgcode" + "github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgerror" + "github.com/cockroachdb/cockroach/pkg/sql/sem/tree" + "github.com/cockroachdb/cockroach/pkg/sql/types" + "github.com/lib/pq/oid" +) + +type unsupportedTypeChecker struct { + version clusterversion.Handle +} + +// NewUnsupportedTypeChecker returns a new tree.UnsupportedTypeChecker that can +// be used to check whether a type is allowed by the current cluster version. +func NewUnsupportedTypeChecker(handle clusterversion.Handle) tree.UnsupportedTypeChecker { + return &unsupportedTypeChecker{version: handle} +} + +var _ tree.UnsupportedTypeChecker = &unsupportedTypeChecker{} + +// CheckType implements the tree.UnsupportedTypeChecker interface. +func (tc *unsupportedTypeChecker) CheckType(ctx context.Context, typ *types.T) error { + var errorTypeString string + if typ.Family() == types.PGLSNFamily { + errorTypeString = "pg_lsn" + } else if typ.Oid() == oid.T_refcursor { + errorTypeString = "refcursor" + } + if errorTypeString != "" && !tc.version.IsActive(ctx, clusterversion.V23_2) { + return pgerror.Newf(pgcode.FeatureNotSupported, + "%s not supported until version 23.2", errorTypeString, + ) + } + return nil +} diff --git a/pkg/sql/sem/tree/col_types_test.go b/pkg/sql/sem/tree/col_types_test.go index c93df3178eca..75ff75867739 100644 --- a/pkg/sql/sem/tree/col_types_test.go +++ b/pkg/sql/sem/tree/col_types_test.go @@ -68,6 +68,7 @@ func TestParseColumnType(t *testing.T) { {"CHAR(11) COLLATE de", types.MakeCollatedString(types.MakeChar(11), "de")}, {"VARCHAR COLLATE en", types.MakeCollatedString(types.VarChar, "en")}, {"VARCHAR(2) COLLATE en", types.MakeCollatedString(types.MakeVarChar(2), "en")}, + {"REFCURSOR", types.RefCursor}, } for i, d := range testData { t.Run(d.str, func(t *testing.T) { diff --git a/pkg/sql/sem/tree/type_check.go b/pkg/sql/sem/tree/type_check.go index 0a01e31c40f2..850b26a564a5 100644 --- a/pkg/sql/sem/tree/type_check.go +++ b/pkg/sql/sem/tree/type_check.go @@ -75,6 +75,10 @@ type SemaContext struct { DateStyle pgdate.DateStyle // IntervalStyle refers to the IntervalStyle to parse as. IntervalStyle duration.IntervalStyle + + // UnsupportedTypeChecker is used to determine whether a builtin data type is + // supported by the current cluster version. It may be unset. + UnsupportedTypeChecker UnsupportedTypeChecker } // SemaProperties is a holder for required and derived properties @@ -599,6 +603,9 @@ func (expr *CastExpr) TypeCheck( if err != nil { return nil, err } + if err = CheckUnsupportedType(ctx, semaCtx, exprType); err != nil { + return nil, err + } expr.Type = exprType canElideCast := true switch { @@ -739,6 +746,9 @@ func (expr *AnnotateTypeExpr) TypeCheck( if err != nil { return nil, err } + if err = CheckUnsupportedType(ctx, semaCtx, annotateType); err != nil { + return nil, err + } expr.Type = annotateType subExpr, err := typeCheckAndRequire( ctx, @@ -3411,3 +3421,24 @@ func getMostSignificantOverload( } return ret, nil } + +// UnsupportedTypeChecker is used to check that a type is supported by the +// current cluster version. It is an interface because some packages cannot +// import the clusterversion package. +type UnsupportedTypeChecker interface { + // CheckType returns an error if the given type is not supported by the + // current cluster version. + CheckType(ctx context.Context, typ *types.T) error +} + +// CheckUnsupportedType returns an error if the given type is not supported by +// the current cluster version. If the given SemaContext is nil or +// uninitialized, CheckUnsupportedType returns nil. +func CheckUnsupportedType(ctx context.Context, semaCtx *SemaContext, typ *types.T) error { + if semaCtx == nil || semaCtx.UnsupportedTypeChecker == nil { + // Sometimes TypeCheck() is called with a nil SemaContext for tests, and + // some (non-test) locations don't initialize all fields of the SemaContext. + return nil + } + return semaCtx.UnsupportedTypeChecker.CheckType(ctx, typ) +} diff --git a/pkg/sql/types/oid.go b/pkg/sql/types/oid.go index 3a727b2c3a33..dd1333dcd20f 100644 --- a/pkg/sql/types/oid.go +++ b/pkg/sql/types/oid.go @@ -85,6 +85,7 @@ var OidToType = map[oid.Oid]*T{ oid.T_oidvector: OidVector, oid.T_pg_lsn: PGLSN, oid.T_record: AnyTuple, + oid.T_refcursor: RefCursor, oid.T_regclass: RegClass, oid.T_regnamespace: RegNamespace, oid.T_regproc: RegProc, @@ -133,6 +134,7 @@ var oidToArrayOid = map[oid.Oid]oid.Oid{ oid.T_oidvector: oid.T__oidvector, oid.T_pg_lsn: oid.T__pg_lsn, oid.T_record: oid.T__record, + oid.T_refcursor: oid.T__refcursor, oid.T_regclass: oid.T__regclass, oid.T_regnamespace: oid.T__regnamespace, oid.T_regproc: oid.T__regproc, diff --git a/pkg/sql/types/types.go b/pkg/sql/types/types.go index 0edc2314952c..94a5a048f8db 100644 --- a/pkg/sql/types/types.go +++ b/pkg/sql/types/types.go @@ -327,6 +327,12 @@ var ( Name = &T{InternalType: InternalType{ Family: StringFamily, Oid: oid.T_name, Locale: &emptyLocale}} + // RefCursor is the type for a variable representing the name of a cursor in a + // PLpgSQL routine. It is equivalent to String, but has a different oid + // (T_refcursor), which makes it display differently. + RefCursor = &T{InternalType: InternalType{ + Family: StringFamily, Oid: oid.T_refcursor, Locale: &emptyLocale}} + // Bytes is the type of a list of raw byte values. Bytes = &T{InternalType: InternalType{ Family: BytesFamily, Oid: oid.T_bytea, Locale: &emptyLocale}} @@ -901,7 +907,7 @@ func MakeChar(width int32) *T { // oidCanBeCollatedString returns true if the given oid is can be a CollatedString. func oidCanBeCollatedString(o oid.Oid) bool { switch o { - case oid.T_text, oid.T_varchar, oid.T_bpchar, oid.T_char, oid.T_name: + case oid.T_text, oid.T_varchar, oid.T_bpchar, oid.T_char, oid.T_name, oid.T_refcursor: return true } return false @@ -1562,6 +1568,8 @@ func (t *T) Name() string { return "varchar" case oid.T_name: return "name" + case oid.T_refcursor: + return "refcursor" } panic(errors.AssertionFailedf("unexpected OID: %d", t.Oid())) @@ -1766,6 +1774,9 @@ func (t *T) SQLStandardNameWithTypmod(haveTypmod bool, typmod int) string { case oid.T_name: // Type modifiers not allowed for name. return "name" + case oid.T_refcursor: + // Type modifiers not allowed for refcursor. + return "refcursor" default: panic(errors.AssertionFailedf("unexpected OID: %d", t.Oid())) } @@ -2325,6 +2336,10 @@ func (t *T) upgradeType() error { t.InternalType.TimePrecisionIsSet = true } case StringFamily, CollatedStringFamily: + if t.InternalType.Oid == oid.T_refcursor { + // Support for REFCURSOR was added after InternalType was deprecated. + break + } // Map string-related visible types to corresponding Oid values. switch t.InternalType.VisibleType { case visibleVARCHAR: @@ -2489,7 +2504,7 @@ func (t *T) downgradeType() error { case StringFamily, CollatedStringFamily: switch t.Oid() { - case oid.T_text: + case oid.T_text, oid.T_refcursor: // Nothing to do. case oid.T_varchar: t.InternalType.VisibleType = visibleVARCHAR @@ -2816,6 +2831,8 @@ func (t *T) stringTypeSQL() string { typName = `"char"` case oid.T_name: typName = "NAME" + case oid.T_refcursor: + typName = "REFCURSOR" } // In general, if there is a specified width we want to print it next to the @@ -2947,7 +2964,6 @@ var postgresPredefinedTypeIssues = map[string]int{ "macaddr8": 45813, "money": 41578, "path": 21286, - "pg_lsn": -1, "txid_snapshot": -1, "xml": 43355, } diff --git a/pkg/sql/types/types_test.go b/pkg/sql/types/types_test.go index 42b787c0a719..e2b39a00c40f 100644 --- a/pkg/sql/types/types_test.go +++ b/pkg/sql/types/types_test.go @@ -393,6 +393,10 @@ func TestTypes(t *testing.T) { Family: StringFamily, Oid: oid.T_name, Locale: &emptyLocale}}}, {Name, MakeScalar(StringFamily, oid.T_name, 0, 0, emptyLocale)}, + {RefCursor, &T{InternalType: InternalType{ + Family: StringFamily, Oid: oid.T_refcursor, Locale: &emptyLocale}}}, + {RefCursor, MakeScalar(StringFamily, oid.T_refcursor, 0, 0, emptyLocale)}, + // TIME {Time, &T{InternalType: InternalType{ Family: TimeFamily, @@ -775,6 +779,7 @@ func TestMarshalCompat(t *testing.T) { {MakeChar(10), InternalType{Family: StringFamily, Oid: oid.T_bpchar, Width: 10, VisibleType: visibleCHAR}}, {QChar, InternalType{Family: StringFamily, Oid: oid.T_char, Width: 1, VisibleType: visibleQCHAR}}, {Name, InternalType{Family: name, Oid: oid.T_name}}, + {RefCursor, InternalType{Family: StringFamily, Oid: oid.T_refcursor}}, } for _, tc := range testCases { @@ -838,6 +843,7 @@ func TestUnmarshalCompat(t *testing.T) { {InternalType{Family: StringFamily, VisibleType: visibleVARCHAR, Width: 20}, MakeVarChar(20)}, {InternalType{Family: StringFamily, VisibleType: visibleCHAR}, typeBpChar}, {InternalType{Family: StringFamily, VisibleType: visibleQCHAR, Width: 1}, QChar}, + {InternalType{Family: StringFamily, Oid: oid.T_refcursor}, RefCursor}, } for _, tc := range testCases { @@ -1113,6 +1119,7 @@ func TestWithoutTypeModifiers(t *testing.T) { {Jsonb, Jsonb}, {Name, Name}, {Uuid, Uuid}, + {RefCursor, RefCursor}, } for _, tc := range testCases { @@ -1142,6 +1149,7 @@ func TestDelimiter(t *testing.T) { {VarChar, ","}, {QChar, ","}, {Name, ","}, + {RefCursor, ","}, {Bytes, ","}, {Date, ","}, {Time, ","}, diff --git a/pkg/workload/schemachange/operation_generator.go b/pkg/workload/schemachange/operation_generator.go index 39ddaf96631e..cf384858c50d 100644 --- a/pkg/workload/schemachange/operation_generator.go +++ b/pkg/workload/schemachange/operation_generator.go @@ -1363,6 +1363,14 @@ func (og *operationGenerator) createTable(ctx context.Context, tx pgx.Tx) (*opSt if err != nil { return nil, err } + // REFCURSOR was added in 23.2. + refCursorNotSupported, err := isClusterVersionLessThan( + ctx, + tx, + clusterversion.ByKey(clusterversion.V23_2)) + if err != nil { + return nil, err + } // Forward indexes for arrays were added in 23.1, so check the index // definitions for them in mixed version states. forwardIndexesOnArraysNotSupported, err := isClusterVersionLessThan( @@ -1465,6 +1473,8 @@ func (og *operationGenerator) createTable(ctx context.Context, tx pgx.Tx) (*opSt {code: pgcode.FeatureNotSupported, condition: hasUnsupportedTSQuery}, {code: pgcode.Syntax, condition: pgLSNNotSupported}, {code: pgcode.FeatureNotSupported, condition: pgLSNNotSupported}, + {code: pgcode.Syntax, condition: refCursorNotSupported}, + {code: pgcode.FeatureNotSupported, condition: refCursorNotSupported}, {code: pgcode.FeatureNotSupported, condition: hasUnsupportedIdxQueries}, {code: pgcode.InvalidTableDefinition, condition: hasUnsupportedIdxQueries}, })