diff --git a/pkg/sql/opt/ordering/scan.go b/pkg/sql/opt/ordering/scan.go index 417cb1b32ce5..15de46c82669 100644 --- a/pkg/sql/opt/ordering/scan.go +++ b/pkg/sql/opt/ordering/scan.go @@ -130,14 +130,20 @@ func scanBuildProvided(expr memo.RelExpr, required *props.OrderingChoice) opt.Or // We generate the longest ordering that this scan can provide, then we trim // it. This is the longest prefix of index columns that are output by the scan // (ignoring constant columns, in the case of constrained scans). - // We start the for loop at the exact prefix since all columns in the exact - // prefix are constant and can be ignored. + outCols := expr.Relational().OutputCols constCols := fds.ComputeClosure(opt.ColSet{}) numCols := index.KeyColumnCount() provided := make(opt.Ordering, 0, numCols) - for i := scan.ExactPrefix; i < numCols; i++ { + for i := 0; i < numCols; i++ { indexCol := index.Column(i) colID := scan.Table.ColumnID(indexCol.Ordinal()) + if i < scan.ExactPrefix && !outCols.Contains(colID) { + // All columns in the exact prefix are constant and can be ignored as long + // as they are not in the output of the scan. If an exact-prefix column is + // in the output, it may still be constant, but can only be ignored if the + // FDs "know" it is constant. This latter case is handled below as normal. + continue + } if constCols.Contains(colID) { // Column constrained to a constant, ignore. continue diff --git a/pkg/sql/opt/xform/testdata/physprops/ordering b/pkg/sql/opt/xform/testdata/physprops/ordering index 61db209f459a..53f6f66406b5 100644 --- a/pkg/sql/opt/xform/testdata/physprops/ordering +++ b/pkg/sql/opt/xform/testdata/physprops/ordering @@ -2899,3 +2899,35 @@ project ├── t0_85393.rowid:10 [as=t0_85393.rowid:2, outer=(10)] ├── t1_85393.c0:13 [as=t1_85393.c0:5, outer=(13)] └── t1_85393.rowid:14 [as=t1_85393.rowid:6, outer=(14)] + +# Regression test for #83793 - include scan columns that are constrained to be +# constant in the provided ordering when they are in the output of the scan. +exec-ddl +CREATE TABLE t83793 ( + a INT, + b STRING AS (a::STRING) STORED, + c STRING AS (a::STRING) VIRTUAL, + UNIQUE (b, a) +); +---- + +opt format=hide-all +SELECT NULL FROM t83793 +WHERE NOT (c NOT SIMILAR TO '') +GROUP BY b HAVING bool_and(NULL); +---- +project + ├── select + │ ├── group-by (streaming) + │ │ ├── project + │ │ │ ├── scan t83793@t83793_b_a_key + │ │ │ │ └── constraint: /2/1: [/'' - /''] + │ │ │ └── projections + │ │ │ └── NULL + │ │ └── aggregations + │ │ └── bool-and + │ │ └── column7 + │ └── filters + │ └── bool_and + └── projections + └── NULL