Skip to content

sql: reject nested array constructors - #174733

Open
Alignyx wants to merge 1 commit into
cockroachdb:masterfrom
Alignyx:fix-146717-reject-nested-array-constructors
Open

sql: reject nested array constructors#174733
Alignyx wants to merge 1 commit into
cockroachdb:masterfrom
Alignyx:fix-146717-reject-nested-array-constructors

Conversation

@Alignyx

@Alignyx Alignyx commented Sep 5, 2026

Copy link
Copy Markdown

Summary

Reject array-valued elements in ARRAY[...] and ARRAY(subquery) through the existing shared array-element support check. This addresses #146717 by reporting the existing unsupported multidimensional-array feature instead of producing an incorrectly formatted nested result.

This is a constructor/type-validation fix, not an implementation of multidimensional arrays or a universal rejection of every nested-array-producing operation. In particular, the existing array_agg(array) exception is deliberately unchanged. Guidance on that remaining scope is requested below.

Problem and root cause

The reported expression is:

SELECT ARRAY[ARRAY['a']]::TEXT;

It succeeds on the baseline but produces {"{a}"}. This quotes the inner array's text as an outer element rather than representing the intended multidimensional value {{a}}. The issue explicitly accepts an unsupported-feature error because multidimensional arrays are not fully supported.

Both ARRAY-constructor paths in the optimizer builder already call types.CheckArrayElementType. That function delegates to IsValidArrayElementType, which rejects unsupported TSQUERY, TSVECTOR and PGVECTOR elements but has no ArrayFamily case. Its default branch therefore accepts an array as an array element. An unsupported nested value can be built and constant-folded before formatting exposes the problem; other execution/encoding paths can reject it later instead.

The missing check is at the feature-support boundary, not simply in the text formatter. Changing the formatter alone would not supply the missing nested-array execution, encoding, or storage support.

How the discrepancy was localized

The investigation compared alternative representations of the same intended multidimensional value:

-- Constructor forms that succeeded on the baseline with incorrect text.
SELECT ARRAY[ARRAY['a']]::TEXT;
SELECT ARRAY[['a']]::TEXT;
SELECT ARRAY(SELECT ARRAY['a'])::TEXT;
SELECT ARRAY(VALUES (ARRAY['a']))::TEXT;

-- Existing rejection controls.
SELECT '{{a}}'::TEXT[]::TEXT;
SELECT ARRAY[ARRAY['a']]::TEXT[][]::TEXT;

Three isolated baseline matrices consistently observed constructor success with {"{a}"}, while the dimensional literal and explicit dimensional annotation rejected the unsupported feature with SQLSTATE 0A000 and a reference to #32552. Row-mode and forced-DistSQL controls did not make the original text result correct.

This is an error-based metamorphic relation: consistency of the support/rejection boundary across equivalent intended constructions, rather than equality between two successful CockroachDB result sets. The error controls do not have executable plans. For the successful baseline constructor, EXPLAIN (OPT, VERBOSE) already contained the incorrectly formatted constant in a VALUES plan. EXPLAIN ANALYZE confirmed execution of a one-row VALUES operator; the separate SELECT returned the incorrect text. The comparison therefore localizes the discrepancy to planning/type-support validation; it is not a claim of two successful runtime branch traces.

On the candidate, the constructors also reject during planning. The literal and type-annotation controls retain their existing errors. Consistency here means the unsupported-feature class/SQLSTATE and feature reference, not identical complete error wording across syntactic forms.

Repair method and scope

The only production change is the missing case in pkg/sql/types/types.go:

case ArrayFamily:
    return false, 32552

CheckArrayElementType converts this into the existing unimplemented-feature error. Reusing the shared predicate covers its existing constructor, scalar-evaluation and type-validation callers without adding ad hoc checks to each syntax form. The constructor rejection is based on element type, including typed NULL/empty inputs, rather than depending on whether an unsupported value happens to be produced at runtime.

The patch does not change types.MakeArray, type serialization, upgradeType, UserDefined, arithmetic, or text formatting. Normal flat arrays, scalar strings containing braces, and arrays of tuples whose fields contain arrays remain supported. Existing TSQUERY/TSVECTOR/PGVECTOR restrictions remain unchanged.

The other eight changed files are tests or fixtures:

  • Add direct element-support regression coverage and the original SQL plus bracket, SELECT, VALUES, empty and NULL constructor cases.
  • Replace two old array fixtures that expected local nested-array success but distributed failure with planning-error expectations.
  • Update evaluator/builder fixtures whose previously accepted nested constructors are now rejected earlier.
  • Rewrite affected optimizer-rule fixtures using supported flat arrays or tuple-containing arrays, retaining their existing rule expectations rather than deleting the coverage.

Relation to the previously closed PR

#168470 targeted #167545, not #146717. It proposed relaxing nested-array unmarshaling for user-defined types; #146717 was cited during review as a risk of admitting incompletely supported arrays-of-arrays. That PR was closed in favor of rejecting domain-of-array creation. The replacement #168715 was merged.

This patch follows the early-rejection direction for a different entry point. The baseline already contains the domain-of-array/tuple creation restrictions, and they remain unchanged. The nested-array unmarshaling assertion is not relaxed, and no UDT exception is introduced. This history supports the distinction in approach; it is not a claim of prior approval of this particular patch.

Completed local verification

The candidate is 49af5ea57c9943cdba56cff708f4fad3241d2bda, based independently on 8812064a015d2faf99d3fc7e15880f94042954b0.

  • The new direct type-support test and native SQL regression fail on unmodified production code and pass on the candidate. The new regression cases were held unchanged across those runs; updates to pre-existing fixtures are separate.
  • Three candidate matrices and eight additional constructor cases pass, including array-valued columns, a scanned subquery, correlation, other element types, empty/NULL elements, and a third dimension. Existing rejection controls and supported controls remain unchanged.
  • The complete selected array, aggregate, and srfs logic files pass in local, local-vec-off, fakedist, fakedist-vec-off and fakedist-disk. The new regression has RUN/PASS records in all five configurations. pg_catalog passes its selected local-only configuration.
  • Final types, parser, tree, eval, normalize, colinfo, optbuilder, norm and SQL-package targets pass. The SQL package's actual 16-shard run is retained; this does not mean every package or every logic configuration in the repository was tested.

These describe completed local validation of the existing candidate, not upstream CI status. No new test execution is implied by opening this PR.

Known limitations and compatibility implications

  1. array_agg(array) remains an exception. Its existing explicitly registered array-input overload can still produce nested output such as {"{b,c}"}. Overload generation first checks a scalar element type, then synthesizes the array-input overload without reapplying this predicate to that array type. It is explicitly blocked from distributed evaluation because nested-array value encoding is unsupported. This PR does not remove that overload or correct its text representation; an existing regression and the candidate's additional checks preserve that behavior.
  2. This is intentionally a behavior change. Some nested constructors that previously succeeded locally now fail, including uses without a final ::TEXT. Applications relying on that incomplete local-only behavior will receive an unsupported-feature error. Ordinary supported one-dimensional arrays are not intended to change.
  3. No multidimensional-array implementation is added. Correct formatting, distributed encoding, storage, ordering and general round-trip behavior for such values remain outside this patch. Keeping internal MakeArray nesting available does not make nested values generally supported SQL values.
  4. This is not a repair for pre-existing invalid descriptors or every possible nested-array entry point. Domain creation restrictions come from the existing baseline, and this change neither reopens them nor claims to repair legacy metadata. Mixed-version execution and a comprehensive audit of every array-producing built-in are not covered by the checks listed above.

The deliberate preservation of array_agg(array) means this should be reviewed as a bounded constructor fix, not as a claim that all concerns about nested arrays have been eliminated.

Questions for review and possible follow-up

Would you like me to continue addressing the remaining nested-array entry points, especially array_agg(array), in this PR or in a separate follow-up? Is preserving that existing overload the preferred compatibility boundary for this constructor fix, or should it also become an unsupported-feature error?

If further rejection work is desired, the next step would be to audit array-input overload registration and other array-producing paths, distinguish nesting operations from flattening operations such as array_cat_agg, and assess the compatibility impact before changing the accepted signatures or results. That follow-up is not implemented or validated here. Full multidimensional support would instead need a broader design across type representation, formatting, execution and encoding; it should not be implied by a formatter-only change or an unmarshaling exception.

Should remaining work be tracked under #146717, under the broader #32552, or in a separate issue? The existing commit has an issue-closing trailer, so the intended tracking boundary should be agreed before merge.

See also: #146717, #32552
Epic: none

Release note (bug fix): Nested ARRAY[...] and ARRAY(subquery) constructors now consistently return an unsupported-feature error instead of producing incorrectly formatted multidimensional arrays.

The array-element support check rejects several unsupported scalar types
but allows arrays. Consequently ARRAY[...] and ARRAY(subquery) can build
nested arrays even though their encoding is unsupported. Casting these
values to text quotes inner arrays as strings and produces wrong results.

Reject array-valued elements through the shared support check, using the
existing multidimensional-array feature issue. Keep internal array types,
arrays of tuples containing arrays, and the separately registered
array_agg(array) overload unchanged.

Add constructor and type-support regressions. Update existing unsupported
constructor expectations and preserve unrelated optimizer-rule coverage
using supported array and tuple expressions.

Resolves: cockroachdb#146717
Epic: None

Release note (bug fix): Nested ARRAY[...] and ARRAY(subquery) constructors
now consistently return an unsupported-feature error instead of producing
incorrectly formatted multidimensional arrays.
@Alignyx
Alignyx requested a review from a team as a code owner September 5, 2026 10:58
@Alignyx
Alignyx requested review from bowencrl and removed request for a team September 5, 2026 10:58
@blathers-crl

blathers-crl Bot commented Sep 5, 2026

Copy link
Copy Markdown

Thank you for contributing to CockroachDB. Please ensure you have followed the guidelines for creating a PR.

My owl senses detect your PR is good for review. Please keep an eye out for any test failures in CI.

🦉 Hoot! I am a Blathers, a bot for CockroachDB. My owner is dev-inf.

@blathers-crl blathers-crl Bot added the O-community Originated from the community label Sep 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

O-community Originated from the community

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant