From 1588a7624d1c025d012b3009b510ba700a420c91 Mon Sep 17 00:00:00 2001 From: Faizan Qazi Date: Fri, 6 Oct 2023 09:52:55 -0400 Subject: [PATCH] pg_catalog: indoption was not encoded correctly Previously, the indoption field inside pg_index was encoded incorrectly, which could cause problems for binary clients. Specifically, an int8 was being sent across the wire, then int2vectors are supposed to be made of int2. To address this, this patch ensures that an int2 is used and adds assertion inside the conversion code (for int2vector) to avoid future problems. Fixes: #111907 Release note (bug fix): indoption inside pg_index was not properly encoded, causing clients to be unable to decode it as int2vector. --- pkg/sql/pg_catalog.go | 2 +- pkg/sql/pgwire/testdata/pgtest/int2vector | 33 +++++++++++++++++++++++ pkg/sql/sem/tree/datum.go | 4 +++ 3 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 pkg/sql/pgwire/testdata/pgtest/int2vector diff --git a/pkg/sql/pg_catalog.go b/pkg/sql/pg_catalog.go index ad1b9e3c9b0b..99487de51009 100644 --- a/pkg/sql/pg_catalog.go +++ b/pkg/sql/pg_catalog.go @@ -1879,7 +1879,7 @@ https://www.postgresql.org/docs/9.5/catalog-pg-index.html`, // Also fill in indoption for each column to indicate if the index // is ASC/DESC and if nulls appear first/last. collationOids := tree.NewDArray(types.Oid) - indoption := tree.NewDArray(types.Int) + indoption := tree.NewDArray(types.Int2) colAttNums := make([]descpb.ColumnID, 0, index.NumKeyColumns()) exprs := make([]string, 0, index.NumKeyColumns()) diff --git a/pkg/sql/pgwire/testdata/pgtest/int2vector b/pkg/sql/pgwire/testdata/pgtest/int2vector new file mode 100644 index 000000000000..ff87ee5c2894 --- /dev/null +++ b/pkg/sql/pgwire/testdata/pgtest/int2vector @@ -0,0 +1,33 @@ +# This test validates that int2vector produces an array +# of int2 objects. Previously CRDB incorrectly was returning +# int8 values as observed in #111907, which would cause problems +# for binary pgwire clients. +send +Query {"String": "DROP TABLE IF EXISTS t"} +Query {"String": "CREATE TABLE t (a int primary key, b text)"} +---- + +until +ReadyForQuery +ReadyForQuery +---- +{"Type":"CommandComplete","CommandTag":"DROP TABLE"} +{"Type":"ReadyForQuery","TxStatus":"I"} +{"Type":"CommandComplete","CommandTag":"CREATE TABLE"} +{"Type":"ReadyForQuery","TxStatus":"I"} + +send +Parse {"Query": "select i.indoption from pg_index i join pg_class c on i.indrelid = c.oid where c.relname = 't';"} +Bind {"ParameterFormatCodes": [0], "ResultFormatCodes": [1]} +Execute +Sync +---- + +until +ReadyForQuery +---- +{"Type":"ParseComplete"} +{"Type":"BindComplete"} +{"Type":"DataRow","Values":[{"binary":"0000000100000000000000150000000100000001000000020002"}]} +{"Type":"CommandComplete","CommandTag":"SELECT 1"} +{"Type":"ReadyForQuery","TxStatus":"I"} diff --git a/pkg/sql/sem/tree/datum.go b/pkg/sql/sem/tree/datum.go index f4330cfe71dc..5c1f8198c9e0 100644 --- a/pkg/sql/sem/tree/datum.go +++ b/pkg/sql/sem/tree/datum.go @@ -5922,6 +5922,10 @@ func NewDName(d string) Datum { // NewDIntVectorFromDArray is a helper routine to create a new *DArray, // initialized from an existing *DArray, with the special oid for IntVector. func NewDIntVectorFromDArray(d *DArray) Datum { + // Sanity: Validate the type of the array, since it should be int2. + if d.ParamTyp != types.Int2 { + panic(errors.AssertionFailedf("int2vector can only be made from int2 not %v", d.ParamTyp)) + } ret := new(DArray) *ret = *d ret.customOid = oid.T_int2vector