From 4a11c7d3b8fdc72a0e493ec4c67cd342350f774b Mon Sep 17 00:00:00 2001 From: Marcus Gartner Date: Wed, 14 Aug 2024 16:13:55 -0400 Subject: [PATCH] opt: fix BPCHAR type and CASE typing This commit addresses inconsistencies from Postgres' behavior. First, it makes the `BPCHAR` type distinct from `CHAR`. The former is a blank-padded character type with no type width, meaning that it could have any length. The latter is a blank-padded character type with a type width of exactly 1 - it is essentially an alias of `CHAR(1)`. Previously, a column of type `BPCHAR` behaved the same as a column of type `CHAR(1)` - it enforced a length limit of 1. Second, the typing of `CASE` and `CASE`-like expressions has been fixed. The branches of these conditionals is no longer forced to have the same type-width. Fixes #127889 Fixes #108360 Release note (bug fix): A bug has been fixed that caused incorrect evaluation of `CASE`, `COALESCE`, and `IF` expressions with branches producing fixed-width string-like types, such as `CHAR`. In addition, the `BPCHAR` type has been fixed so that it no longer incorrectly imposes a length limit of 1. --- .../tests/3node-tenant/generated_test.go | 7 +++ .../local-read-committed/generated_test.go | 7 +++ .../local-repeatable-read/generated_test.go | 7 +++ pkg/sql/logictest/testdata/logic_test/bpchar | 27 ++++++++ pkg/sql/logictest/testdata/logic_test/case | 46 ++++++++++++++ pkg/sql/logictest/testdata/logic_test/cast | 2 +- pkg/sql/logictest/testdata/logic_test/decimal | 2 +- .../testdata/logic_test/drop_function | 30 +++++++++ .../logictest/testdata/logic_test/grant_table | 62 +++++++++---------- .../logictest/testdata/logic_test/pg_builtins | 6 +- pkg/sql/logictest/testdata/logic_test/typing | 6 +- .../tests/fakedist-disk/generated_test.go | 7 +++ .../tests/fakedist-vec-off/generated_test.go | 7 +++ .../tests/fakedist/generated_test.go | 7 +++ .../generated_test.go | 7 +++ .../tests/local-mixed-24.1/generated_test.go | 7 +++ .../tests/local-mixed-24.2/generated_test.go | 7 +++ .../tests/local-vec-off/generated_test.go | 7 +++ .../logictest/tests/local/generated_test.go | 7 +++ pkg/sql/opt/optbuilder/scalar.go | 8 +-- pkg/sql/opt/optbuilder/testdata/scalar | 8 +-- pkg/sql/opt/xform/testdata/external/tpcc | 19 +++--- .../xform/testdata/external/tpcc-later-stats | 19 +++--- .../opt/xform/testdata/external/tpcc-no-stats | 19 +++--- .../testdata/external/tpcc-read-committed | 19 +++--- pkg/sql/opt/xform/testdata/rules/select | 2 +- .../comparator_generated_test.go | 5 ++ pkg/sql/sem/builtins/fixed_oids.go | 62 +++++++++---------- pkg/sql/sem/tree/overload.go | 8 ++- pkg/sql/types/types.go | 7 +++ 30 files changed, 315 insertions(+), 119 deletions(-) create mode 100644 pkg/sql/logictest/testdata/logic_test/bpchar diff --git a/pkg/ccl/logictestccl/tests/3node-tenant/generated_test.go b/pkg/ccl/logictestccl/tests/3node-tenant/generated_test.go index 3d3b1a5888aa..7b59b6e6b41c 100644 --- a/pkg/ccl/logictestccl/tests/3node-tenant/generated_test.go +++ b/pkg/ccl/logictestccl/tests/3node-tenant/generated_test.go @@ -333,6 +333,13 @@ func TestTenantLogic_bit( runLogicTest(t, "bit") } +func TestTenantLogic_bpchar( + t *testing.T, +) { + defer leaktest.AfterTest(t)() + runLogicTest(t, "bpchar") +} + func TestTenantLogic_builtin_function( t *testing.T, ) { diff --git a/pkg/ccl/logictestccl/tests/local-read-committed/generated_test.go b/pkg/ccl/logictestccl/tests/local-read-committed/generated_test.go index 694eb3c25c38..a6b83b474221 100644 --- a/pkg/ccl/logictestccl/tests/local-read-committed/generated_test.go +++ b/pkg/ccl/logictestccl/tests/local-read-committed/generated_test.go @@ -331,6 +331,13 @@ func TestReadCommittedLogic_bit( runLogicTest(t, "bit") } +func TestReadCommittedLogic_bpchar( + t *testing.T, +) { + defer leaktest.AfterTest(t)() + runLogicTest(t, "bpchar") +} + func TestReadCommittedLogic_builtin_function( t *testing.T, ) { diff --git a/pkg/ccl/logictestccl/tests/local-repeatable-read/generated_test.go b/pkg/ccl/logictestccl/tests/local-repeatable-read/generated_test.go index d0f9c3a80dfa..025e9bc40f6a 100644 --- a/pkg/ccl/logictestccl/tests/local-repeatable-read/generated_test.go +++ b/pkg/ccl/logictestccl/tests/local-repeatable-read/generated_test.go @@ -331,6 +331,13 @@ func TestRepeatableReadLogic_bit( runLogicTest(t, "bit") } +func TestRepeatableReadLogic_bpchar( + t *testing.T, +) { + defer leaktest.AfterTest(t)() + runLogicTest(t, "bpchar") +} + func TestRepeatableReadLogic_builtin_function( t *testing.T, ) { diff --git a/pkg/sql/logictest/testdata/logic_test/bpchar b/pkg/sql/logictest/testdata/logic_test/bpchar new file mode 100644 index 000000000000..46377711358b --- /dev/null +++ b/pkg/sql/logictest/testdata/logic_test/bpchar @@ -0,0 +1,27 @@ +query T +SELECT 'foo'::BPCHAR +---- +foo + +statement ok +CREATE TABLE t (c BPCHAR PRIMARY KEY, FAMILY (c)) + +statement ok +INSERT INTO t VALUES ('foo'), ('ba'), ('c'), ('foobarbaz') + +query T rowsort +SELECT c FROM t +---- +foo +ba +c +foobarbaz + +query T +SELECT create_statement FROM [SHOW CREATE TABLE t] +---- +CREATE TABLE public.t ( + c BPCHAR NOT NULL, + CONSTRAINT t_pkey PRIMARY KEY (c ASC), + FAMILY fam_0_c (c) +) diff --git a/pkg/sql/logictest/testdata/logic_test/case b/pkg/sql/logictest/testdata/logic_test/case index 6c6e40dbba01..3bf03681830a 100644 --- a/pkg/sql/logictest/testdata/logic_test/case +++ b/pkg/sql/logictest/testdata/logic_test/case @@ -48,3 +48,49 @@ SELECT CASE WHEN f = 0 FROM a; subtest end + +# Regression test for #127889. CASE-like expressions should not impose type +# widths of one branch on other branches. +subtest regression_127889 + +query T +SELECT CASE WHEN true THEN 'foo'::TEXT ELSE 'b'::CHAR END +---- +foo + +query T +SELECT COALESCE(NULL::CHAR, 'bar'::CHAR(2)) +---- +ba + +query T +SELECT IF(false, 'foo'::CHAR, 'bar'::CHAR(2)) +---- +ba + +query T +SELECT CASE WHEN false THEN 'b'::CHAR ELSE 'foo'::TEXT END +---- +foo + +query T +SELECT (CASE WHEN false THEN 'b'::CHAR ELSE 'foo'::TEXT END)::CHAR +---- +f + +query T +SELECT (CASE WHEN false THEN 'b'::CHAR ELSE 'foo'::TEXT END)::BPCHAR +---- +foo + +query R +SELECT CASE WHEN true THEN 1.2345::DECIMAL(5, 4) ELSE NULL::DECIMAL(10, 2) END +---- +1.2345 + +query R +SELECT CASE WHEN false THEN NULL::DECIMAL(10, 2) ELSE 1.2345::DECIMAL(5, 4) END +---- +1.2345 + +subtest end diff --git a/pkg/sql/logictest/testdata/logic_test/cast b/pkg/sql/logictest/testdata/logic_test/cast index a7d0893034bc..300d4f5c069c 100644 --- a/pkg/sql/logictest/testdata/logic_test/cast +++ b/pkg/sql/logictest/testdata/logic_test/cast @@ -1446,7 +1446,7 @@ CREATE TABLE def_assn_cast ( id INT4, a INT4 DEFAULT 1.0::FLOAT4, b VARCHAR DEFAULT 'true'::BOOL, - c NAME DEFAULT 'foo'::BPCHAR + c NAME DEFAULT 'foo'::CHAR ) statement ok diff --git a/pkg/sql/logictest/testdata/logic_test/decimal b/pkg/sql/logictest/testdata/logic_test/decimal index d6ff3b95dde3..901eaf807807 100644 --- a/pkg/sql/logictest/testdata/logic_test/decimal +++ b/pkg/sql/logictest/testdata/logic_test/decimal @@ -468,7 +468,7 @@ NaN NaN NaN NaN NaN # TODO(#115679): There are a few differences vs postgres in the number of # decimal places and negative zeros. query RRRRR -WITH v(id, x) AS (VALUES (1, '0'::numeric), (2, '1'::numeric), (3, '-1'::numeric), +WITH v(id, x) AS (VALUES (1, '0'::numeric), (2, '1'::numeric), (3, '-1'::numeric), (4, '4.2'::numeric), (5, 'inf'::numeric), (6, '-inf'::numeric), (7, 'nan'::numeric) ) SELECT x1, x2, diff --git a/pkg/sql/logictest/testdata/logic_test/drop_function b/pkg/sql/logictest/testdata/logic_test/drop_function index a513811845ae..f2331a72cce8 100644 --- a/pkg/sql/logictest/testdata/logic_test/drop_function +++ b/pkg/sql/logictest/testdata/logic_test/drop_function @@ -326,3 +326,33 @@ DROP TABLE t1_with_b_2_ref; statement ok DROP FUNCTION f_b; + +statement ok +CREATE FUNCTION f_char(c CHAR) RETURNS INT LANGUAGE SQL AS 'SELECT 1' + +statement ok +DROP FUNCTION f_char(BPCHAR) + +statement ok +CREATE FUNCTION f_char(c CHAR(2)) RETURNS INT LANGUAGE SQL AS 'SELECT 1' + +statement ok +DROP FUNCTION f_char(BPCHAR) + +statement ok +CREATE FUNCTION f_char(c BPCHAR) RETURNS INT LANGUAGE SQL AS 'SELECT 1' + +statement ok +DROP FUNCTION f_char(BPCHAR) + +statement ok +CREATE FUNCTION f_char(c BPCHAR) RETURNS INT LANGUAGE SQL AS 'SELECT 1' + +statement ok +DROP FUNCTION f_char(CHAR) + +statement ok +CREATE FUNCTION f_char(c BPCHAR) RETURNS INT LANGUAGE SQL AS 'SELECT 1' + +statement ok +DROP FUNCTION f_char(CHAR(2)) diff --git a/pkg/sql/logictest/testdata/logic_test/grant_table b/pkg/sql/logictest/testdata/logic_test/grant_table index 4ec5e7cfe695..1994865b5a23 100644 --- a/pkg/sql/logictest/testdata/logic_test/grant_table +++ b/pkg/sql/logictest/testdata/logic_test/grant_table @@ -250,18 +250,18 @@ test pg_catalog box2d test pg_catalog box2d[] type admin ALL false test pg_catalog box2d[] type public USAGE false test pg_catalog box2d[] type root ALL false +test pg_catalog bpchar type admin ALL false +test pg_catalog bpchar type public USAGE false +test pg_catalog bpchar type root ALL false +test pg_catalog bpchar[] type admin ALL false +test pg_catalog bpchar[] type public USAGE false +test pg_catalog bpchar[] type root ALL false test pg_catalog bytes type admin ALL false test pg_catalog bytes type public USAGE false test pg_catalog bytes type root ALL false test pg_catalog bytes[] type admin ALL false test pg_catalog bytes[] type public USAGE false test pg_catalog bytes[] type root ALL false -test pg_catalog char type admin ALL false -test pg_catalog char type public USAGE false -test pg_catalog char type root ALL false -test pg_catalog char[] type admin ALL false -test pg_catalog char[] type public USAGE false -test pg_catalog char[] type root ALL false test pg_catalog date type admin ALL false test pg_catalog date type public USAGE false test pg_catalog date type root ALL false @@ -651,14 +651,14 @@ test pg_catalog box2d type admin ALL test pg_catalog box2d type root ALL false test pg_catalog box2d[] type admin ALL false test pg_catalog box2d[] type root ALL false +test pg_catalog bpchar type admin ALL false +test pg_catalog bpchar type root ALL false +test pg_catalog bpchar[] type admin ALL false +test pg_catalog bpchar[] type root ALL false test pg_catalog bytes type admin ALL false test pg_catalog bytes type root ALL false test pg_catalog bytes[] type admin ALL false test pg_catalog bytes[] type root ALL false -test pg_catalog char type admin ALL false -test pg_catalog char type root ALL false -test pg_catalog char[] type admin ALL false -test pg_catalog char[] type root ALL false test pg_catalog date type admin ALL false test pg_catalog date type root ALL false test pg_catalog date[] type admin ALL false @@ -810,9 +810,9 @@ test pg_catalog vector[] type root ALL test pg_catalog void type admin ALL false test pg_catalog void type root ALL false test public NULL schema admin ALL true -test public NULL schema root ALL true test public NULL schema public CREATE false test public NULL schema public USAGE false +test public NULL schema root ALL true # With no database set, we show the grants everywhere statement ok @@ -1279,14 +1279,14 @@ a pg_catalog box2d type admin a pg_catalog box2d type root ALL false a pg_catalog box2d[] type admin ALL false a pg_catalog box2d[] type root ALL false +a pg_catalog bpchar type admin ALL false +a pg_catalog bpchar type root ALL false +a pg_catalog bpchar[] type admin ALL false +a pg_catalog bpchar[] type root ALL false a pg_catalog bytes type admin ALL false a pg_catalog bytes type root ALL false a pg_catalog bytes[] type admin ALL false a pg_catalog bytes[] type root ALL false -a pg_catalog char type admin ALL false -a pg_catalog char type root ALL false -a pg_catalog char[] type admin ALL false -a pg_catalog char[] type root ALL false a pg_catalog date type admin ALL false a pg_catalog date type root ALL false a pg_catalog date[] type admin ALL false @@ -1463,14 +1463,14 @@ defaultdb pg_catalog box2d type admin defaultdb pg_catalog box2d type root ALL false defaultdb pg_catalog box2d[] type admin ALL false defaultdb pg_catalog box2d[] type root ALL false +defaultdb pg_catalog bpchar type admin ALL false +defaultdb pg_catalog bpchar type root ALL false +defaultdb pg_catalog bpchar[] type admin ALL false +defaultdb pg_catalog bpchar[] type root ALL false defaultdb pg_catalog bytes type admin ALL false defaultdb pg_catalog bytes type root ALL false defaultdb pg_catalog bytes[] type admin ALL false defaultdb pg_catalog bytes[] type root ALL false -defaultdb pg_catalog char type admin ALL false -defaultdb pg_catalog char type root ALL false -defaultdb pg_catalog char[] type admin ALL false -defaultdb pg_catalog char[] type root ALL false defaultdb pg_catalog date type admin ALL false defaultdb pg_catalog date type root ALL false defaultdb pg_catalog date[] type admin ALL false @@ -1647,14 +1647,14 @@ postgres pg_catalog box2d type admin postgres pg_catalog box2d type root ALL false postgres pg_catalog box2d[] type admin ALL false postgres pg_catalog box2d[] type root ALL false +postgres pg_catalog bpchar type admin ALL false +postgres pg_catalog bpchar type root ALL false +postgres pg_catalog bpchar[] type admin ALL false +postgres pg_catalog bpchar[] type root ALL false postgres pg_catalog bytes type admin ALL false postgres pg_catalog bytes type root ALL false postgres pg_catalog bytes[] type admin ALL false postgres pg_catalog bytes[] type root ALL false -postgres pg_catalog char type admin ALL false -postgres pg_catalog char type root ALL false -postgres pg_catalog char[] type admin ALL false -postgres pg_catalog char[] type root ALL false postgres pg_catalog date type admin ALL false postgres pg_catalog date type root ALL false postgres pg_catalog date[] type admin ALL false @@ -1831,14 +1831,14 @@ system pg_catalog box2d type admin system pg_catalog box2d type root ALL false system pg_catalog box2d[] type admin ALL false system pg_catalog box2d[] type root ALL false +system pg_catalog bpchar type admin ALL false +system pg_catalog bpchar type root ALL false +system pg_catalog bpchar[] type admin ALL false +system pg_catalog bpchar[] type root ALL false system pg_catalog bytes type admin ALL false system pg_catalog bytes type root ALL false system pg_catalog bytes[] type admin ALL false system pg_catalog bytes[] type root ALL false -system pg_catalog char type admin ALL false -system pg_catalog char type root ALL false -system pg_catalog char[] type admin ALL false -system pg_catalog char[] type root ALL false system pg_catalog date type admin ALL false system pg_catalog date type root ALL false system pg_catalog date[] type admin ALL false @@ -2404,14 +2404,14 @@ test pg_catalog box2d type admin test pg_catalog box2d type root ALL false test pg_catalog box2d[] type admin ALL false test pg_catalog box2d[] type root ALL false +test pg_catalog bpchar type admin ALL false +test pg_catalog bpchar type root ALL false +test pg_catalog bpchar[] type admin ALL false +test pg_catalog bpchar[] type root ALL false test pg_catalog bytes type admin ALL false test pg_catalog bytes type root ALL false test pg_catalog bytes[] type admin ALL false test pg_catalog bytes[] type root ALL false -test pg_catalog char type admin ALL false -test pg_catalog char type root ALL false -test pg_catalog char[] type admin ALL false -test pg_catalog char[] type root ALL false test pg_catalog date type admin ALL false test pg_catalog date type root ALL false test pg_catalog date[] type admin ALL false diff --git a/pkg/sql/logictest/testdata/logic_test/pg_builtins b/pkg/sql/logictest/testdata/logic_test/pg_builtins index 4f3fbc153585..c31c5a342a90 100644 --- a/pkg/sql/logictest/testdata/logic_test/pg_builtins +++ b/pkg/sql/logictest/testdata/logic_test/pg_builtins @@ -521,7 +521,7 @@ ORDER BY t.oid ---- text 25 -1 float8 701 -1 -bpchar 1042 5 +bpchar 1042 -1 varchar 1043 68 bit 1560 1 varbit 1562 16 @@ -539,7 +539,7 @@ ORDER BY t.oid ---- text NULL float8 NULL -bpchar 1 +bpchar NULL varchar 64 bit 1 varbit 16 @@ -558,7 +558,7 @@ ORDER BY t.oid ---- text NULL float8 NULL -bpchar 1 +bpchar NULL varchar 64 bit 1 varbit 16 diff --git a/pkg/sql/logictest/testdata/logic_test/typing b/pkg/sql/logictest/testdata/logic_test/typing index 78923573e608..4a411a75f888 100644 --- a/pkg/sql/logictest/testdata/logic_test/typing +++ b/pkg/sql/logictest/testdata/logic_test/typing @@ -289,15 +289,12 @@ WHERE t102110_1.t NOT BETWEEN t102110_1.t AND (CASE WHEN NULL THEN t102110_2.c ELSE t102110_1.t END); ---- -# IF is typed differently (Postgres does not support IF). query T SELECT t102110_1.t FROM t102110_1, t102110_2 WHERE t102110_1.t NOT BETWEEN t102110_1.t AND IF(NULL, t102110_2.c, t102110_1.t); ---- -tt -# TODO(#108360): implicit casts from STRING to CHAR should use bpchar. statement ok CREATE TABLE t108360_1 (t TEXT); INSERT INTO t108360_1 VALUES ('tt'); @@ -306,13 +303,12 @@ statement ok CREATE TABLE t108360_2 (c CHAR); INSERT INTO t108360_2 VALUES ('c'); -# This returns one row with 'tt' in Postgres. The results are different because -# Postgres casts t108360_1.t to bpchar rather than char. query T SELECT (CASE WHEN t108360_1.t > t108360_2.c THEN t108360_1.t ELSE t108360_2.c END) FROM t108360_1, t108360_2 WHERE t108360_1.t = (CASE WHEN t108360_1.t > t108360_2.c THEN t108360_1.t ELSE t108360_2.c END); ---- +tt # Static analysis types should never make it to execution. statement ok diff --git a/pkg/sql/logictest/tests/fakedist-disk/generated_test.go b/pkg/sql/logictest/tests/fakedist-disk/generated_test.go index 102c324a2f70..c1d4376783da 100644 --- a/pkg/sql/logictest/tests/fakedist-disk/generated_test.go +++ b/pkg/sql/logictest/tests/fakedist-disk/generated_test.go @@ -288,6 +288,13 @@ func TestLogic_bit( runLogicTest(t, "bit") } +func TestLogic_bpchar( + t *testing.T, +) { + defer leaktest.AfterTest(t)() + runLogicTest(t, "bpchar") +} + func TestLogic_builtin_function( 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 956c4091d289..221eb0d8cd59 100644 --- a/pkg/sql/logictest/tests/fakedist-vec-off/generated_test.go +++ b/pkg/sql/logictest/tests/fakedist-vec-off/generated_test.go @@ -288,6 +288,13 @@ func TestLogic_bit( runLogicTest(t, "bit") } +func TestLogic_bpchar( + t *testing.T, +) { + defer leaktest.AfterTest(t)() + runLogicTest(t, "bpchar") +} + func TestLogic_builtin_function( t *testing.T, ) { diff --git a/pkg/sql/logictest/tests/fakedist/generated_test.go b/pkg/sql/logictest/tests/fakedist/generated_test.go index 40d87dd6a0a1..7c40fd7f07da 100644 --- a/pkg/sql/logictest/tests/fakedist/generated_test.go +++ b/pkg/sql/logictest/tests/fakedist/generated_test.go @@ -288,6 +288,13 @@ func TestLogic_bit( runLogicTest(t, "bit") } +func TestLogic_bpchar( + t *testing.T, +) { + defer leaktest.AfterTest(t)() + runLogicTest(t, "bpchar") +} + func TestLogic_builtin_function( 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 1231a0a6cdee..b781cf772698 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 @@ -288,6 +288,13 @@ func TestLogic_bit( runLogicTest(t, "bit") } +func TestLogic_bpchar( + t *testing.T, +) { + defer leaktest.AfterTest(t)() + runLogicTest(t, "bpchar") +} + func TestLogic_builtin_function( t *testing.T, ) { diff --git a/pkg/sql/logictest/tests/local-mixed-24.1/generated_test.go b/pkg/sql/logictest/tests/local-mixed-24.1/generated_test.go index 5d697dbc409e..c6a76b91e04d 100644 --- a/pkg/sql/logictest/tests/local-mixed-24.1/generated_test.go +++ b/pkg/sql/logictest/tests/local-mixed-24.1/generated_test.go @@ -288,6 +288,13 @@ func TestLogic_bit( runLogicTest(t, "bit") } +func TestLogic_bpchar( + t *testing.T, +) { + defer leaktest.AfterTest(t)() + runLogicTest(t, "bpchar") +} + func TestLogic_builtin_function( t *testing.T, ) { diff --git a/pkg/sql/logictest/tests/local-mixed-24.2/generated_test.go b/pkg/sql/logictest/tests/local-mixed-24.2/generated_test.go index 6ef739501923..6d307204f218 100644 --- a/pkg/sql/logictest/tests/local-mixed-24.2/generated_test.go +++ b/pkg/sql/logictest/tests/local-mixed-24.2/generated_test.go @@ -288,6 +288,13 @@ func TestLogic_bit( runLogicTest(t, "bit") } +func TestLogic_bpchar( + t *testing.T, +) { + defer leaktest.AfterTest(t)() + runLogicTest(t, "bpchar") +} + func TestLogic_builtin_function( 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 47c66a5daf0a..9ab8edc3da22 100644 --- a/pkg/sql/logictest/tests/local-vec-off/generated_test.go +++ b/pkg/sql/logictest/tests/local-vec-off/generated_test.go @@ -288,6 +288,13 @@ func TestLogic_bit( runLogicTest(t, "bit") } +func TestLogic_bpchar( + t *testing.T, +) { + defer leaktest.AfterTest(t)() + runLogicTest(t, "bpchar") +} + func TestLogic_builtin_function( t *testing.T, ) { diff --git a/pkg/sql/logictest/tests/local/generated_test.go b/pkg/sql/logictest/tests/local/generated_test.go index eae6f2b132d3..d043af6678f1 100644 --- a/pkg/sql/logictest/tests/local/generated_test.go +++ b/pkg/sql/logictest/tests/local/generated_test.go @@ -288,6 +288,13 @@ func TestLogic_bit( runLogicTest(t, "bit") } +func TestLogic_bpchar( + t *testing.T, +) { + defer leaktest.AfterTest(t)() + runLogicTest(t, "bpchar") +} + func TestLogic_builtin_function( t *testing.T, ) { diff --git a/pkg/sql/opt/optbuilder/scalar.go b/pkg/sql/opt/optbuilder/scalar.go index 5755c1035106..5f1d2d01f8db 100644 --- a/pkg/sql/opt/optbuilder/scalar.go +++ b/pkg/sql/opt/optbuilder/scalar.go @@ -249,7 +249,7 @@ func (b *Builder) buildScalar( for i := range t.Whens { condExpr := t.Whens[i].Cond.(tree.TypedExpr) cond := b.buildScalar(condExpr, inScope, nil, nil, colRefs) - valExpr, ok := eval.ReType(t.Whens[i].Val.(tree.TypedExpr), valType) + valExpr, ok := eval.ReType(t.Whens[i].Val.(tree.TypedExpr), valType.WithoutTypeModifiers()) if !ok { panic(pgerror.Newf( pgcode.DatatypeMismatch, @@ -263,7 +263,7 @@ func (b *Builder) buildScalar( // Add the ELSE expression to the end of whens as a raw scalar expression. var orElse opt.ScalarExpr if t.Else != nil { - elseExpr, ok := eval.ReType(t.Else.(tree.TypedExpr), valType) + elseExpr, ok := eval.ReType(t.Else.(tree.TypedExpr), valType.WithoutTypeModifiers()) if !ok { panic(pgerror.Newf( pgcode.DatatypeMismatch, @@ -289,7 +289,7 @@ func (b *Builder) buildScalar( // The type of the CoalesceExpr might be different than the inputs (e.g. // when they are NULL). Force all inputs to be the same type, so that we // build coalesce operator with the correct type. - expr, ok := eval.ReType(t.TypedExprAt(i), typ) + expr, ok := eval.ReType(t.TypedExprAt(i), typ.WithoutTypeModifiers()) if !ok { panic(pgerror.Newf( pgcode.DatatypeMismatch, @@ -339,7 +339,7 @@ func (b *Builder) buildScalar( ifTrueExpr := reType(t.True.(tree.TypedExpr), valType) ifTrue := b.buildScalar(ifTrueExpr, inScope, nil, nil, colRefs) whens := memo.ScalarListExpr{b.factory.ConstructWhen(memo.TrueSingleton, ifTrue)} - orElseExpr, ok := eval.ReType(t.Else.(tree.TypedExpr), valType) + orElseExpr, ok := eval.ReType(t.Else.(tree.TypedExpr), valType.WithoutTypeModifiers()) if !ok { panic(pgerror.Newf( pgcode.DatatypeMismatch, diff --git a/pkg/sql/opt/optbuilder/testdata/scalar b/pkg/sql/opt/optbuilder/testdata/scalar index 49ec545bcb27..8d320a5f39ce 100644 --- a/pkg/sql/opt/optbuilder/testdata/scalar +++ b/pkg/sql/opt/optbuilder/testdata/scalar @@ -1642,7 +1642,7 @@ project │ │ └── columns: c:5 t102110_2.rowid:6!null t102110_2.crdb_internal_mvcc_timestamp:7 t102110_2.tableoid:8 │ └── filters (true) └── filters - └── NOT ((t:1 >= t:1) AND (t:1 <= CASE WHEN NULL THEN t:1::CHAR ELSE c:5 END)) + └── NOT ((t:1 >= t:1) AND (t:1 <= CASE WHEN NULL THEN t:1::BPCHAR ELSE c:5::BPCHAR END)) # IF is typed differently (Postgres does not support IF). build @@ -1662,7 +1662,7 @@ project │ │ └── columns: c:5 t102110_2.rowid:6!null t102110_2.crdb_internal_mvcc_timestamp:7 t102110_2.tableoid:8 │ └── filters (true) └── filters - └── NOT ((t:1 >= t:1) AND (t:1 <= CASE NULL WHEN true THEN c:5 ELSE t:1::CHAR END)) + └── NOT ((t:1 >= t:1) AND (t:1 <= CASE NULL WHEN true THEN c:5 ELSE t:1::BPCHAR END)) # TODO(#108360): implicit casts from STRING to CHAR should use bpchar. exec-ddl @@ -1690,6 +1690,6 @@ project │ │ │ └── columns: t108360_2.c:5 t108360_2.rowid:6!null t108360_2.crdb_internal_mvcc_timestamp:7 t108360_2.tableoid:8 │ │ └── filters (true) │ └── filters - │ └── t:1 = CASE WHEN t:1 > t108360_2.c:5 THEN t:1::CHAR ELSE t108360_2.c:5 END + │ └── t:1 = CASE WHEN t:1 > t108360_2.c:5 THEN t:1::BPCHAR ELSE t108360_2.c:5::BPCHAR END └── projections - └── CASE WHEN t:1 > t108360_2.c:5 THEN t:1::CHAR ELSE t108360_2.c:5 END [as=c:9] + └── CASE WHEN t:1 > t108360_2.c:5 THEN t:1::BPCHAR ELSE t108360_2.c:5::BPCHAR END [as=c:9] diff --git a/pkg/sql/opt/xform/testdata/external/tpcc b/pkg/sql/opt/xform/testdata/external/tpcc index 62f714bce82d..ab515df43338 100644 --- a/pkg/sql/opt/xform/testdata/external/tpcc +++ b/pkg/sql/opt/xform/testdata/external/tpcc @@ -580,11 +580,11 @@ RETURNING CASE c_credit WHEN 'BC' THEN "left"(c_data, 200) ELSE '' END ---- project - ├── columns: c_first:4 c_middle:5 c_last:6 c_street_1:7 c_street_2:8 c_city:9 c_state:10 c_zip:11 c_phone:12 c_since:13 c_credit:14 c_credit_lim:15 c_discount:16 c_balance:17 case:53 + ├── columns: c_first:4 c_middle:5 c_last:6 c_street_1:7 c_street_2:8 c_city:9 c_state:10 c_zip:11 c_phone:12 c_since:13 c_credit:14 c_credit_lim:15 c_discount:16 c_balance:17 case:54 ├── cardinality: [0 - 1] ├── volatile, mutations ├── key: () - ├── fd: ()-->(4-17,53) + ├── fd: ()-->(4-17,54) ├── update customer │ ├── columns: c_id:1!null c_d_id:2!null c_w_id:3!null c_first:4 c_middle:5 c_last:6 c_street_1:7 c_street_2:8 c_city:9 c_state:10 c_zip:11 c_phone:12 c_since:13 c_credit:14 c_credit_lim:15 c_discount:16 c_balance:17 c_data:21 │ ├── fetch columns: c_id:24 c_d_id:25 c_w_id:26 c_first:27 c_middle:28 c_last:29 c_street_1:30 c_street_2:31 c_city:32 c_state:33 c_zip:34 c_phone:35 c_since:36 c_credit:37 c_credit_lim:38 c_discount:39 c_balance:40 c_ytd_payment:41 c_payment_cnt:42 c_delivery_cnt:43 c_data:44 @@ -592,7 +592,7 @@ project │ │ ├── c_balance_cast:51 => c_balance:17 │ │ ├── c_ytd_payment_cast:52 => c_ytd_payment:18 │ │ ├── c_payment_cnt_new:49 => c_payment_cnt:19 - │ │ └── c_data_new:50 => c_data:21 + │ │ └── c_data_cast:53 => c_data:21 │ ├── return-mapping: │ │ ├── c_id:24 => c_id:1 │ │ ├── c_d_id:25 => c_d_id:2 @@ -611,17 +611,17 @@ project │ │ ├── c_credit_lim:38 => c_credit_lim:15 │ │ ├── c_discount:39 => c_discount:16 │ │ ├── c_balance_cast:51 => c_balance:17 - │ │ └── c_data_new:50 => c_data:21 + │ │ └── c_data_cast:53 => c_data:21 │ ├── cardinality: [0 - 1] │ ├── volatile, mutations │ ├── key: () │ ├── fd: ()-->(1-17,21) │ └── project - │ ├── columns: c_balance_cast:51 c_ytd_payment_cast:52 c_payment_cnt_new:49 c_data_new:50 c_id:24!null c_d_id:25!null c_w_id:26!null c_first:27 c_middle:28 c_last:29 c_street_1:30 c_street_2:31 c_city:32 c_state:33 c_zip:34 c_phone:35 c_since:36 c_credit:37 c_credit_lim:38 c_discount:39 c_balance:40 c_ytd_payment:41 c_payment_cnt:42 c_delivery_cnt:43 c_data:44 + │ ├── columns: c_balance_cast:51 c_ytd_payment_cast:52 c_data_cast:53 c_payment_cnt_new:49 c_id:24!null c_d_id:25!null c_w_id:26!null c_first:27 c_middle:28 c_last:29 c_street_1:30 c_street_2:31 c_city:32 c_state:33 c_zip:34 c_phone:35 c_since:36 c_credit:37 c_credit_lim:38 c_discount:39 c_balance:40 c_ytd_payment:41 c_payment_cnt:42 c_delivery_cnt:43 c_data:44 │ ├── cardinality: [0 - 1] │ ├── immutable │ ├── key: () - │ ├── fd: ()-->(24-44,49-52) + │ ├── fd: ()-->(24-44,49,51-53) │ ├── scan customer │ │ ├── columns: c_id:24!null c_d_id:25!null c_w_id:26!null c_first:27 c_middle:28 c_last:29 c_street_1:30 c_street_2:31 c_city:32 c_state:33 c_zip:34 c_phone:35 c_since:36 c_credit:37 c_credit_lim:38 c_discount:39 c_balance:40 c_ytd_payment:41 c_payment_cnt:42 c_delivery_cnt:43 c_data:44 │ │ ├── constraint: /26/25/24: [/10/5/1343 - /10/5/1343] @@ -633,10 +633,11 @@ project │ │ └── c_balance:40 - 3860.61 │ ├── assignment-cast: DECIMAL(12,2) [as=c_ytd_payment_cast:52, outer=(41), immutable] │ │ └── c_ytd_payment:41 + 3860.61 - │ ├── c_payment_cnt:42 + 1 [as=c_payment_cnt_new:49, outer=(42), immutable] - │ └── CASE c_credit:37 WHEN 'BC' THEN left((((((c_id:24::STRING || c_d_id:25::STRING) || c_w_id:26::STRING) || '5') || '10') || '3860.61') || c_data:44, 500)::VARCHAR(500) ELSE c_data:44 END [as=c_data_new:50, outer=(24-26,37,44), immutable] + │ ├── assignment-cast: VARCHAR(500) [as=c_data_cast:53, outer=(24-26,37,44), immutable] + │ │ └── CASE c_credit:37 WHEN 'BC' THEN left((((((c_id:24::STRING || c_d_id:25::STRING) || c_w_id:26::STRING) || '5') || '10') || '3860.61') || c_data:44, 500)::VARCHAR ELSE c_data:44::VARCHAR END + │ └── c_payment_cnt:42 + 1 [as=c_payment_cnt_new:49, outer=(42), immutable] └── projections - └── CASE c_credit:14 WHEN 'BC' THEN left(c_data:21, 200) ELSE '' END [as=case:53, outer=(14,21), immutable] + └── CASE c_credit:14 WHEN 'BC' THEN left(c_data:21, 200) ELSE '' END [as=case:54, outer=(14,21), immutable] opt format=hide-qual INSERT INTO history diff --git a/pkg/sql/opt/xform/testdata/external/tpcc-later-stats b/pkg/sql/opt/xform/testdata/external/tpcc-later-stats index d7eb4296cf0b..446f1056146e 100644 --- a/pkg/sql/opt/xform/testdata/external/tpcc-later-stats +++ b/pkg/sql/opt/xform/testdata/external/tpcc-later-stats @@ -579,11 +579,11 @@ RETURNING CASE c_credit WHEN 'BC' THEN "left"(c_data, 200) ELSE '' END ---- project - ├── columns: c_first:4 c_middle:5 c_last:6 c_street_1:7 c_street_2:8 c_city:9 c_state:10 c_zip:11 c_phone:12 c_since:13 c_credit:14 c_credit_lim:15 c_discount:16 c_balance:17 case:53 + ├── columns: c_first:4 c_middle:5 c_last:6 c_street_1:7 c_street_2:8 c_city:9 c_state:10 c_zip:11 c_phone:12 c_since:13 c_credit:14 c_credit_lim:15 c_discount:16 c_balance:17 case:54 ├── cardinality: [0 - 1] ├── volatile, mutations ├── key: () - ├── fd: ()-->(4-17,53) + ├── fd: ()-->(4-17,54) ├── update customer │ ├── columns: c_id:1!null c_d_id:2!null c_w_id:3!null c_first:4 c_middle:5 c_last:6 c_street_1:7 c_street_2:8 c_city:9 c_state:10 c_zip:11 c_phone:12 c_since:13 c_credit:14 c_credit_lim:15 c_discount:16 c_balance:17 c_data:21 │ ├── fetch columns: c_id:24 c_d_id:25 c_w_id:26 c_first:27 c_middle:28 c_last:29 c_street_1:30 c_street_2:31 c_city:32 c_state:33 c_zip:34 c_phone:35 c_since:36 c_credit:37 c_credit_lim:38 c_discount:39 c_balance:40 c_ytd_payment:41 c_payment_cnt:42 c_delivery_cnt:43 c_data:44 @@ -591,7 +591,7 @@ project │ │ ├── c_balance_cast:51 => c_balance:17 │ │ ├── c_ytd_payment_cast:52 => c_ytd_payment:18 │ │ ├── c_payment_cnt_new:49 => c_payment_cnt:19 - │ │ └── c_data_new:50 => c_data:21 + │ │ └── c_data_cast:53 => c_data:21 │ ├── return-mapping: │ │ ├── c_id:24 => c_id:1 │ │ ├── c_d_id:25 => c_d_id:2 @@ -610,17 +610,17 @@ project │ │ ├── c_credit_lim:38 => c_credit_lim:15 │ │ ├── c_discount:39 => c_discount:16 │ │ ├── c_balance_cast:51 => c_balance:17 - │ │ └── c_data_new:50 => c_data:21 + │ │ └── c_data_cast:53 => c_data:21 │ ├── cardinality: [0 - 1] │ ├── volatile, mutations │ ├── key: () │ ├── fd: ()-->(1-17,21) │ └── project - │ ├── columns: c_balance_cast:51 c_ytd_payment_cast:52 c_payment_cnt_new:49 c_data_new:50 c_id:24!null c_d_id:25!null c_w_id:26!null c_first:27 c_middle:28 c_last:29 c_street_1:30 c_street_2:31 c_city:32 c_state:33 c_zip:34 c_phone:35 c_since:36 c_credit:37 c_credit_lim:38 c_discount:39 c_balance:40 c_ytd_payment:41 c_payment_cnt:42 c_delivery_cnt:43 c_data:44 + │ ├── columns: c_balance_cast:51 c_ytd_payment_cast:52 c_data_cast:53 c_payment_cnt_new:49 c_id:24!null c_d_id:25!null c_w_id:26!null c_first:27 c_middle:28 c_last:29 c_street_1:30 c_street_2:31 c_city:32 c_state:33 c_zip:34 c_phone:35 c_since:36 c_credit:37 c_credit_lim:38 c_discount:39 c_balance:40 c_ytd_payment:41 c_payment_cnt:42 c_delivery_cnt:43 c_data:44 │ ├── cardinality: [0 - 1] │ ├── immutable │ ├── key: () - │ ├── fd: ()-->(24-44,49-52) + │ ├── fd: ()-->(24-44,49,51-53) │ ├── scan customer │ │ ├── columns: c_id:24!null c_d_id:25!null c_w_id:26!null c_first:27 c_middle:28 c_last:29 c_street_1:30 c_street_2:31 c_city:32 c_state:33 c_zip:34 c_phone:35 c_since:36 c_credit:37 c_credit_lim:38 c_discount:39 c_balance:40 c_ytd_payment:41 c_payment_cnt:42 c_delivery_cnt:43 c_data:44 │ │ ├── constraint: /26/25/24: [/10/5/1343 - /10/5/1343] @@ -632,10 +632,11 @@ project │ │ └── c_balance:40 - 3860.61 │ ├── assignment-cast: DECIMAL(12,2) [as=c_ytd_payment_cast:52, outer=(41), immutable] │ │ └── c_ytd_payment:41 + 3860.61 - │ ├── c_payment_cnt:42 + 1 [as=c_payment_cnt_new:49, outer=(42), immutable] - │ └── CASE c_credit:37 WHEN 'BC' THEN left((((((c_id:24::STRING || c_d_id:25::STRING) || c_w_id:26::STRING) || '5') || '10') || '3860.61') || c_data:44, 500)::VARCHAR(500) ELSE c_data:44 END [as=c_data_new:50, outer=(24-26,37,44), immutable] + │ ├── assignment-cast: VARCHAR(500) [as=c_data_cast:53, outer=(24-26,37,44), immutable] + │ │ └── CASE c_credit:37 WHEN 'BC' THEN left((((((c_id:24::STRING || c_d_id:25::STRING) || c_w_id:26::STRING) || '5') || '10') || '3860.61') || c_data:44, 500)::VARCHAR ELSE c_data:44::VARCHAR END + │ └── c_payment_cnt:42 + 1 [as=c_payment_cnt_new:49, outer=(42), immutable] └── projections - └── CASE c_credit:14 WHEN 'BC' THEN left(c_data:21, 200) ELSE '' END [as=case:53, outer=(14,21), immutable] + └── CASE c_credit:14 WHEN 'BC' THEN left(c_data:21, 200) ELSE '' END [as=case:54, outer=(14,21), immutable] opt format=hide-qual INSERT INTO history diff --git a/pkg/sql/opt/xform/testdata/external/tpcc-no-stats b/pkg/sql/opt/xform/testdata/external/tpcc-no-stats index b46dabe9cbdb..568165f14dc8 100644 --- a/pkg/sql/opt/xform/testdata/external/tpcc-no-stats +++ b/pkg/sql/opt/xform/testdata/external/tpcc-no-stats @@ -577,11 +577,11 @@ RETURNING CASE c_credit WHEN 'BC' THEN "left"(c_data, 200) ELSE '' END ---- project - ├── columns: c_first:4 c_middle:5 c_last:6 c_street_1:7 c_street_2:8 c_city:9 c_state:10 c_zip:11 c_phone:12 c_since:13 c_credit:14 c_credit_lim:15 c_discount:16 c_balance:17 case:53 + ├── columns: c_first:4 c_middle:5 c_last:6 c_street_1:7 c_street_2:8 c_city:9 c_state:10 c_zip:11 c_phone:12 c_since:13 c_credit:14 c_credit_lim:15 c_discount:16 c_balance:17 case:54 ├── cardinality: [0 - 1] ├── volatile, mutations ├── key: () - ├── fd: ()-->(4-17,53) + ├── fd: ()-->(4-17,54) ├── update customer │ ├── columns: c_id:1!null c_d_id:2!null c_w_id:3!null c_first:4 c_middle:5 c_last:6 c_street_1:7 c_street_2:8 c_city:9 c_state:10 c_zip:11 c_phone:12 c_since:13 c_credit:14 c_credit_lim:15 c_discount:16 c_balance:17 c_data:21 │ ├── fetch columns: c_id:24 c_d_id:25 c_w_id:26 c_first:27 c_middle:28 c_last:29 c_street_1:30 c_street_2:31 c_city:32 c_state:33 c_zip:34 c_phone:35 c_since:36 c_credit:37 c_credit_lim:38 c_discount:39 c_balance:40 c_ytd_payment:41 c_payment_cnt:42 c_delivery_cnt:43 c_data:44 @@ -589,7 +589,7 @@ project │ │ ├── c_balance_cast:51 => c_balance:17 │ │ ├── c_ytd_payment_cast:52 => c_ytd_payment:18 │ │ ├── c_payment_cnt_new:49 => c_payment_cnt:19 - │ │ └── c_data_new:50 => c_data:21 + │ │ └── c_data_cast:53 => c_data:21 │ ├── return-mapping: │ │ ├── c_id:24 => c_id:1 │ │ ├── c_d_id:25 => c_d_id:2 @@ -608,17 +608,17 @@ project │ │ ├── c_credit_lim:38 => c_credit_lim:15 │ │ ├── c_discount:39 => c_discount:16 │ │ ├── c_balance_cast:51 => c_balance:17 - │ │ └── c_data_new:50 => c_data:21 + │ │ └── c_data_cast:53 => c_data:21 │ ├── cardinality: [0 - 1] │ ├── volatile, mutations │ ├── key: () │ ├── fd: ()-->(1-17,21) │ └── project - │ ├── columns: c_balance_cast:51 c_ytd_payment_cast:52 c_payment_cnt_new:49 c_data_new:50 c_id:24!null c_d_id:25!null c_w_id:26!null c_first:27 c_middle:28 c_last:29 c_street_1:30 c_street_2:31 c_city:32 c_state:33 c_zip:34 c_phone:35 c_since:36 c_credit:37 c_credit_lim:38 c_discount:39 c_balance:40 c_ytd_payment:41 c_payment_cnt:42 c_delivery_cnt:43 c_data:44 + │ ├── columns: c_balance_cast:51 c_ytd_payment_cast:52 c_data_cast:53 c_payment_cnt_new:49 c_id:24!null c_d_id:25!null c_w_id:26!null c_first:27 c_middle:28 c_last:29 c_street_1:30 c_street_2:31 c_city:32 c_state:33 c_zip:34 c_phone:35 c_since:36 c_credit:37 c_credit_lim:38 c_discount:39 c_balance:40 c_ytd_payment:41 c_payment_cnt:42 c_delivery_cnt:43 c_data:44 │ ├── cardinality: [0 - 1] │ ├── immutable │ ├── key: () - │ ├── fd: ()-->(24-44,49-52) + │ ├── fd: ()-->(24-44,49,51-53) │ ├── scan customer │ │ ├── columns: c_id:24!null c_d_id:25!null c_w_id:26!null c_first:27 c_middle:28 c_last:29 c_street_1:30 c_street_2:31 c_city:32 c_state:33 c_zip:34 c_phone:35 c_since:36 c_credit:37 c_credit_lim:38 c_discount:39 c_balance:40 c_ytd_payment:41 c_payment_cnt:42 c_delivery_cnt:43 c_data:44 │ │ ├── constraint: /26/25/24: [/10/5/1343 - /10/5/1343] @@ -630,10 +630,11 @@ project │ │ └── c_balance:40 - 3860.61 │ ├── assignment-cast: DECIMAL(12,2) [as=c_ytd_payment_cast:52, outer=(41), immutable] │ │ └── c_ytd_payment:41 + 3860.61 - │ ├── c_payment_cnt:42 + 1 [as=c_payment_cnt_new:49, outer=(42), immutable] - │ └── CASE c_credit:37 WHEN 'BC' THEN left((((((c_id:24::STRING || c_d_id:25::STRING) || c_w_id:26::STRING) || '5') || '10') || '3860.61') || c_data:44, 500)::VARCHAR(500) ELSE c_data:44 END [as=c_data_new:50, outer=(24-26,37,44), immutable] + │ ├── assignment-cast: VARCHAR(500) [as=c_data_cast:53, outer=(24-26,37,44), immutable] + │ │ └── CASE c_credit:37 WHEN 'BC' THEN left((((((c_id:24::STRING || c_d_id:25::STRING) || c_w_id:26::STRING) || '5') || '10') || '3860.61') || c_data:44, 500)::VARCHAR ELSE c_data:44::VARCHAR END + │ └── c_payment_cnt:42 + 1 [as=c_payment_cnt_new:49, outer=(42), immutable] └── projections - └── CASE c_credit:14 WHEN 'BC' THEN left(c_data:21, 200) ELSE '' END [as=case:53, outer=(14,21), immutable] + └── CASE c_credit:14 WHEN 'BC' THEN left(c_data:21, 200) ELSE '' END [as=case:54, outer=(14,21), immutable] opt format=hide-qual INSERT INTO history diff --git a/pkg/sql/opt/xform/testdata/external/tpcc-read-committed b/pkg/sql/opt/xform/testdata/external/tpcc-read-committed index 1f9a0229c9ed..09ef9884b07b 100644 --- a/pkg/sql/opt/xform/testdata/external/tpcc-read-committed +++ b/pkg/sql/opt/xform/testdata/external/tpcc-read-committed @@ -589,11 +589,11 @@ RETURNING CASE c_credit WHEN 'BC' THEN "left"(c_data, 200) ELSE '' END ---- project - ├── columns: c_first:4 c_middle:5 c_last:6 c_street_1:7 c_street_2:8 c_city:9 c_state:10 c_zip:11 c_phone:12 c_since:13 c_credit:14 c_credit_lim:15 c_discount:16 c_balance:17 case:53 + ├── columns: c_first:4 c_middle:5 c_last:6 c_street_1:7 c_street_2:8 c_city:9 c_state:10 c_zip:11 c_phone:12 c_since:13 c_credit:14 c_credit_lim:15 c_discount:16 c_balance:17 case:54 ├── cardinality: [0 - 1] ├── volatile, mutations ├── key: () - ├── fd: ()-->(4-17,53) + ├── fd: ()-->(4-17,54) ├── update customer │ ├── columns: c_id:1!null c_d_id:2!null c_w_id:3!null c_first:4 c_middle:5 c_last:6 c_street_1:7 c_street_2:8 c_city:9 c_state:10 c_zip:11 c_phone:12 c_since:13 c_credit:14 c_credit_lim:15 c_discount:16 c_balance:17 c_data:21 │ ├── fetch columns: c_id:24 c_d_id:25 c_w_id:26 c_first:27 c_middle:28 c_last:29 c_street_1:30 c_street_2:31 c_city:32 c_state:33 c_zip:34 c_phone:35 c_since:36 c_credit:37 c_credit_lim:38 c_discount:39 c_balance:40 c_ytd_payment:41 c_payment_cnt:42 c_delivery_cnt:43 c_data:44 @@ -601,7 +601,7 @@ project │ │ ├── c_balance_cast:51 => c_balance:17 │ │ ├── c_ytd_payment_cast:52 => c_ytd_payment:18 │ │ ├── c_payment_cnt_new:49 => c_payment_cnt:19 - │ │ └── c_data_new:50 => c_data:21 + │ │ └── c_data_cast:53 => c_data:21 │ ├── return-mapping: │ │ ├── c_id:24 => c_id:1 │ │ ├── c_d_id:25 => c_d_id:2 @@ -620,17 +620,17 @@ project │ │ ├── c_credit_lim:38 => c_credit_lim:15 │ │ ├── c_discount:39 => c_discount:16 │ │ ├── c_balance_cast:51 => c_balance:17 - │ │ └── c_data_new:50 => c_data:21 + │ │ └── c_data_cast:53 => c_data:21 │ ├── cardinality: [0 - 1] │ ├── volatile, mutations │ ├── key: () │ ├── fd: ()-->(1-17,21) │ └── project - │ ├── columns: c_balance_cast:51 c_ytd_payment_cast:52 c_payment_cnt_new:49 c_data_new:50 c_id:24!null c_d_id:25!null c_w_id:26!null c_first:27 c_middle:28 c_last:29 c_street_1:30 c_street_2:31 c_city:32 c_state:33 c_zip:34 c_phone:35 c_since:36 c_credit:37 c_credit_lim:38 c_discount:39 c_balance:40 c_ytd_payment:41 c_payment_cnt:42 c_delivery_cnt:43 c_data:44 + │ ├── columns: c_balance_cast:51 c_ytd_payment_cast:52 c_data_cast:53 c_payment_cnt_new:49 c_id:24!null c_d_id:25!null c_w_id:26!null c_first:27 c_middle:28 c_last:29 c_street_1:30 c_street_2:31 c_city:32 c_state:33 c_zip:34 c_phone:35 c_since:36 c_credit:37 c_credit_lim:38 c_discount:39 c_balance:40 c_ytd_payment:41 c_payment_cnt:42 c_delivery_cnt:43 c_data:44 │ ├── cardinality: [0 - 1] │ ├── immutable │ ├── key: () - │ ├── fd: ()-->(24-44,49-52) + │ ├── fd: ()-->(24-44,49,51-53) │ ├── scan customer │ │ ├── columns: c_id:24!null c_d_id:25!null c_w_id:26!null c_first:27 c_middle:28 c_last:29 c_street_1:30 c_street_2:31 c_city:32 c_state:33 c_zip:34 c_phone:35 c_since:36 c_credit:37 c_credit_lim:38 c_discount:39 c_balance:40 c_ytd_payment:41 c_payment_cnt:42 c_delivery_cnt:43 c_data:44 │ │ ├── constraint: /26/25/24: [/10/5/1343 - /10/5/1343] @@ -642,10 +642,11 @@ project │ │ └── c_balance:40 - 3860.61 │ ├── assignment-cast: DECIMAL(12,2) [as=c_ytd_payment_cast:52, outer=(41), immutable] │ │ └── c_ytd_payment:41 + 3860.61 - │ ├── c_payment_cnt:42 + 1 [as=c_payment_cnt_new:49, outer=(42), immutable] - │ └── CASE c_credit:37 WHEN 'BC' THEN left((((((c_id:24::STRING || c_d_id:25::STRING) || c_w_id:26::STRING) || '5') || '10') || '3860.61') || c_data:44, 500)::VARCHAR(500) ELSE c_data:44 END [as=c_data_new:50, outer=(24-26,37,44), immutable] + │ ├── assignment-cast: VARCHAR(500) [as=c_data_cast:53, outer=(24-26,37,44), immutable] + │ │ └── CASE c_credit:37 WHEN 'BC' THEN left((((((c_id:24::STRING || c_d_id:25::STRING) || c_w_id:26::STRING) || '5') || '10') || '3860.61') || c_data:44, 500)::VARCHAR ELSE c_data:44::VARCHAR END + │ └── c_payment_cnt:42 + 1 [as=c_payment_cnt_new:49, outer=(42), immutable] └── projections - └── CASE c_credit:14 WHEN 'BC' THEN left(c_data:21, 200) ELSE '' END [as=case:53, outer=(14,21), immutable] + └── CASE c_credit:14 WHEN 'BC' THEN left(c_data:21, 200) ELSE '' END [as=case:54, outer=(14,21), immutable] opt format=hide-qual isolation=ReadCommitted INSERT INTO history diff --git a/pkg/sql/opt/xform/testdata/rules/select b/pkg/sql/opt/xform/testdata/rules/select index d363cbff9b54..4fd8fbf574cb 100644 --- a/pkg/sql/opt/xform/testdata/rules/select +++ b/pkg/sql/opt/xform/testdata/rules/select @@ -13134,7 +13134,7 @@ select ├── scan t85356 │ └── columns: c0:1 └── filters - ├── c0:1 = CASE WHEN (c0:1 IS NOT DISTINCT FROM CAST(NULL AS DECIMAL(15,3))) AND CAST(NULL AS BOOL) THEN c0:1 ELSE 1.100 END [outer=(1), immutable, constraints=(/1: (/NULL - ])] + ├── c0:1 = CASE WHEN (c0:1 IS NOT DISTINCT FROM CAST(NULL AS DECIMAL(15,3))) AND CAST(NULL AS BOOL) THEN c0:1::DECIMAL ELSE 1.1 END [outer=(1), immutable, constraints=(/1: (/NULL - ])] └── c0:1 = 2 [outer=(1), immutable, constraints=(/1: [/2 - /2]; tight), fd=()-->(1)] exec-ddl diff --git a/pkg/sql/schemachanger/comparator_generated_test.go b/pkg/sql/schemachanger/comparator_generated_test.go index 6b8b3ab66473..e35b35b7c7df 100644 --- a/pkg/sql/schemachanger/comparator_generated_test.go +++ b/pkg/sql/schemachanger/comparator_generated_test.go @@ -168,6 +168,11 @@ func TestSchemaChangeComparator_bit(t *testing.T) { var logicTestFile = "pkg/sql/logictest/testdata/logic_test/bit" runSchemaChangeComparatorTest(t, logicTestFile) } +func TestSchemaChangeComparator_bpchar(t *testing.T) { + defer leaktest.AfterTest(t)() + var logicTestFile = "pkg/sql/logictest/testdata/logic_test/bpchar" + runSchemaChangeComparatorTest(t, logicTestFile) +} func TestSchemaChangeComparator_builtin_function(t *testing.T) { defer leaktest.AfterTest(t)() var logicTestFile = "pkg/sql/logictest/testdata/logic_test/builtin_function" diff --git a/pkg/sql/sem/builtins/fixed_oids.go b/pkg/sql/sem/builtins/fixed_oids.go index 698e61dcc1fc..52f3080b3fa4 100644 --- a/pkg/sql/sem/builtins/fixed_oids.go +++ b/pkg/sql/sem/builtins/fixed_oids.go @@ -1842,10 +1842,10 @@ var builtinOidsArray = []string{ 1867: `geography_recv(input: anyelement) -> geography`, 1868: `geography_out(geography: geography) -> bytes`, 1869: `geography_in(input: anyelement) -> geography`, - 1870: `bpcharsend(char: char) -> bytes`, - 1871: `bpcharrecv(input: anyelement) -> char`, - 1872: `bpcharout(char: char) -> bytes`, - 1873: `bpcharin(input: anyelement) -> char`, + 1870: `bpcharsend(bpchar: bpchar) -> bytes`, + 1871: `bpcharrecv(input: anyelement) -> bpchar`, + 1872: `bpcharout(bpchar: bpchar) -> bytes`, + 1873: `bpcharin(input: anyelement) -> bpchar`, 1874: `geometry_send(geometry: geometry) -> bytes`, 1875: `geometry_recv(input: anyelement) -> geometry`, 1876: `geometry_out(geometry: geometry) -> bytes`, @@ -2291,30 +2291,30 @@ var builtinOidsArray = []string{ 2321: `date(timestamptz: timestamptz) -> date`, 2322: `date(string: string) -> date`, 2323: `date(date: date) -> date`, - 2324: `bpchar(uuid: uuid) -> char`, - 2325: `bpchar(bit: bit) -> char`, - 2326: `bpchar(box2d: box2d) -> char`, - 2327: `bpchar(interval: interval) -> char`, - 2328: `bpchar(decimal: decimal) -> char`, - 2329: `bpchar(tuple: tuple) -> char`, - 2330: `bpchar(date: date) -> char`, - 2331: `bpchar(oid: oid) -> char`, - 2332: `bpchar(geometry: geometry) -> char`, - 2333: `bpchar(time: time) -> char`, - 2334: `bpchar(tsvector: tsvector) -> char`, - 2335: `bpchar(bool: bool) -> char`, - 2336: `bpchar(int: int) -> char`, - 2337: `bpchar(timestamp: timestamp) -> char`, - 2338: `bpchar(timestamptz: timestamptz) -> char`, - 2339: `bpchar(tsquery: tsquery) -> char`, - 2340: `bpchar(float: float) -> char`, - 2341: `bpchar(geography: geography) -> char`, - 2342: `bpchar(inet: inet) -> char`, - 2343: `bpchar(timetz: timetz) -> char`, - 2344: `bpchar(void: void) -> char`, - 2345: `bpchar(bytes: bytes) -> char`, - 2346: `bpchar(jsonb: jsonb) -> char`, - 2347: `bpchar(string: string) -> char`, + 2324: `bpchar(uuid: uuid) -> bpchar`, + 2325: `bpchar(bit: bit) -> bpchar`, + 2326: `bpchar(box2d: box2d) -> bpchar`, + 2327: `bpchar(interval: interval) -> bpchar`, + 2328: `bpchar(decimal: decimal) -> bpchar`, + 2329: `bpchar(tuple: tuple) -> bpchar`, + 2330: `bpchar(date: date) -> bpchar`, + 2331: `bpchar(oid: oid) -> bpchar`, + 2332: `bpchar(geometry: geometry) -> bpchar`, + 2333: `bpchar(time: time) -> bpchar`, + 2334: `bpchar(tsvector: tsvector) -> bpchar`, + 2335: `bpchar(bool: bool) -> bpchar`, + 2336: `bpchar(int: int) -> bpchar`, + 2337: `bpchar(timestamp: timestamp) -> bpchar`, + 2338: `bpchar(timestamptz: timestamptz) -> bpchar`, + 2339: `bpchar(tsquery: tsquery) -> bpchar`, + 2340: `bpchar(float: float) -> bpchar`, + 2341: `bpchar(geography: geography) -> bpchar`, + 2342: `bpchar(inet: inet) -> bpchar`, + 2343: `bpchar(timetz: timetz) -> bpchar`, + 2344: `bpchar(void: void) -> bpchar`, + 2345: `bpchar(bytes: bytes) -> bpchar`, + 2346: `bpchar(jsonb: jsonb) -> bpchar`, + 2347: `bpchar(string: string) -> bpchar`, 2348: `numeric(interval: interval) -> decimal`, 2349: `numeric(decimal: decimal) -> decimal`, 2350: `numeric(date: date) -> decimal`, @@ -2389,7 +2389,7 @@ var builtinOidsArray = []string{ 2419: `pg_lsn(pg_lsn: pg_lsn) -> pg_lsn`, 2420: `varchar(pg_lsn: pg_lsn) -> varchar`, 2421: `text(pg_lsn: pg_lsn) -> string`, - 2422: `bpchar(pg_lsn: pg_lsn) -> char`, + 2422: `bpchar(pg_lsn: pg_lsn) -> bpchar`, 2423: `name(pg_lsn: pg_lsn) -> name`, 2424: `char(pg_lsn: pg_lsn) -> "char"`, 2425: `max(arg1: pg_lsn) -> anyelement`, @@ -2469,7 +2469,7 @@ var builtinOidsArray = []string{ 2501: `refcursorrecv(input: anyelement) -> refcursor`, 2502: `refcursor(refcursor: refcursor) -> refcursor`, 2503: `refcursor(string: string) -> refcursor`, - 2504: `bpchar(refcursor: refcursor) -> char`, + 2504: `bpchar(refcursor: refcursor) -> bpchar`, 2505: `char(refcursor: refcursor) -> "char"`, 2506: `name(refcursor: refcursor) -> name`, 2507: `text(refcursor: refcursor) -> string`, @@ -2592,7 +2592,7 @@ var builtinOidsArray = []string{ 2624: `name(vector: vector) -> name`, 2625: `text(vector: vector) -> string`, 2626: `varchar(vector: vector) -> varchar`, - 2627: `bpchar(vector: vector) -> char`, + 2627: `bpchar(vector: vector) -> bpchar`, 2628: `vector(string: string) -> vector`, 2629: `vector(vector: vector) -> vector`, 2630: `cosine_distance(v1: vector, v2: vector) -> float`, diff --git a/pkg/sql/sem/tree/overload.go b/pkg/sql/sem/tree/overload.go index 7761e6c354d0..8854a46913fc 100644 --- a/pkg/sql/sem/tree/overload.go +++ b/pkg/sql/sem/tree/overload.go @@ -417,7 +417,7 @@ type TypeList interface { // Match checks if all types in the TypeList match the corresponding elements in types. Match(types []*types.T) bool // MatchIdentical is similar to match but checks that the types are identical matches, - //instead of equivalent matches. See types.T.Equivalent and types.T.Identical. + // instead of equivalent matches. See types.T.Equivalent and types.T.Identical. MatchIdentical(types []*types.T) bool // MatchAt checks if the parameter type at index i of the TypeList matches type typ. // In all implementations, types.Null will match with each parameter type, allowing @@ -493,7 +493,11 @@ func (p ParamTypes) MatchAt(typ *types.T, i int) bool { // MatchAtIdentical is part of the TypeList interface. func (p ParamTypes) MatchAtIdentical(typ *types.T, i int) bool { - return i < len(p) && (typ.Family() == types.UnknownFamily || p[i].Typ.Identical(typ)) + return i < len(p) && (typ.Family() == types.UnknownFamily || + p[i].Typ.Identical(typ) || + // Special case for CHAR, CHAR(N), and BPCHAR which are not "identical" + // but have the same OID. See #129007. + (p[i].Typ.Oid() == oid.T_bpchar && typ.Oid() == oid.T_bpchar)) } // MatchLen is part of the TypeList interface. diff --git a/pkg/sql/types/types.go b/pkg/sql/types/types.go index ff496d52f20c..76e697b27555 100644 --- a/pkg/sql/types/types.go +++ b/pkg/sql/types/types.go @@ -100,6 +100,7 @@ import ( // | VARCHAR(N) | STRING | T_varchar | 0 | N | // | CHAR | STRING | T_bpchar | 0 | 1 | // | CHAR(N) | STRING | T_bpchar | 0 | N | +// | BPCHAR | STRING | T_bpchar | 0 | 0 | // | "char" | STRING | T_char | 0 | 0 | // | NAME | STRING | T_name | 0 | 0 | // | | | | | | @@ -1624,6 +1625,9 @@ func (t *T) Name() string { case oid.T_text: return "string" case oid.T_bpchar: + if t.Width() == 0 { + return "bpchar" + } return "char" case oid.T_char: // Yes, that's the name. The ways of PostgreSQL are inscrutable. @@ -2954,6 +2958,9 @@ func (t *T) stringTypeSQL() string { case oid.T_varchar: typName = "VARCHAR" case oid.T_bpchar: + if t.Width() == 0 { + return "BPCHAR" + } typName = "CHAR" case oid.T_char: // Yes, that's the name. The ways of PostgreSQL are inscrutable.