December 26, 2024·4 min read·engineeringcockroachdbsqlcompatibilitytypes

CockroachDB 24.3.2 restores legacy VARCHAR comparison typing

A session setting restores comparisons that stricter overload resolution rejected. Wire-protocol tests show why a parameter's declared type matters even when its text looks like a string.

A parameter that looks like text in a log can still arrive at the database with a UUID or boolean type. That distinction is central to CockroachDB 24.3.2, released on December 26. The release adds legacy_varchar_typing, enabled by default, to restore earlier comparison type checking involving VARCHAR columns. Disabling it retains stricter behavior that can reject queries previously accepted.

The backport in pull request 137943 describes an unintended type-checking change associated with new unpreferred overloads. The compatibility setting makes type checking and overload resolution ignore those overloads. This repairs application compatibility through a defined session option rather than assuming that a stricter type system can be introduced without changing accepted SQL.

I appreciate PostgreSQL wire compatibility as a practical advantage of CockroachDB. This patch shows why compatibility includes parameter types carried by that protocol. Looking only at the SQL text can miss information that changes which operator the server is able to resolve.

Parameter types participate in comparison resolution

The patch's wire-protocol regression test creates a table with a UUID primary key and a VARCHAR column named v. It then prepares SELECT id FROM t WHERE v = $1 while declaring the parameter as UUID. Another preparation declares the parameter as boolean. Both queries succeed with the legacy setting enabled, even though the table is empty in this test.

The empty result is useful evidence about the stage involved. It establishes that the server accepts and executes the comparison without needing a matching row. The compatibility issue arises in determining whether the typed comparison is supported. It is not dependent on finding a particular stored value that produces an unusual answer.

With legacy_varchar_typing disabled, the same typed preparations fail with unsupported comparison operator messages for VARCHAR compared with UUID or boolean. The tests also exercise the stricter behavior against PostgreSQL. The newly explicit setting therefore separates CockroachDB's historical acceptance from the stricter compatibility behavior represented by that test.

This explains why rewriting a parameter's displayed value is not a complete diagnosis. The SQL placeholder does not show the type declared in the protocol message. An application binding a UUID has supplied different type information from an application binding text, even if both values print the same characters. The server's overload resolution receives that distinction.

The setting changes accepted expressions

The release notes document the session option directly. The default restores earlier behavior, while turning it off exposes the stricter checks.

SET legacy_varchar_typing = on;

The alternative below selects stricter comparison typing for the session. It can cause previously successful queries to return an unsupported-operator error.

SET legacy_varchar_typing = off;

These are type-checking choices, not changes to the table's column declaration. The stored column remains VARCHAR in the regression test. Selecting the legacy mode changes which comparison forms the server accepts when it analyzes expressions involving that column and typed operands.

The release notes say explicit casts can repair queries rejected by stricter typing. The intended comparison determines which conversion belongs in the SQL. Making the parameter text and making the column another type express different operations. A blanket instruction to cast whichever side is convenient would skip the question of what values the application intends to compare.

Cached planning must notice the session change

The patch also records the legacy flag in the optimizer memo and includes it in the memo's staleness check. Its test changes the session flag and verifies that the stored memo is considered stale. This is necessary because an existing analyzed plan can contain decisions made under a different typing policy.

Changing the session setting therefore has implications beyond the next expression reaching the type checker. Reusing analysis produced under the earlier setting would undermine the new choice. The implementation makes the policy part of deciding whether cached optimization state remains valid for the current session.

That detail is useful when interpreting a compatibility switch. The setting is not merely a display flag read when an error is formatted. It changes semantic analysis, and the cache must preserve agreement with that analysis. The patch connects configuration, overload selection and memo validity explicitly.

I prefer an explicit compatibility boundary here because a maintenance release needs to restore applications without hiding the stricter rule. The default preserves the earlier accepted comparisons, while the off setting exposes the expressions that need a clearer conversion under stricter typing.

The patch also exposes the setting through the session-variable machinery, including its reported value. That makes the selected policy inspectable alongside the connection configuration when a typed comparison behaves differently across sessions.

The December release is consequently small in its public changelog but specific in its mechanism. Its regression test preserves parameter type information through preparation, binding and execution. The session option controls which overloads participate in analysis, and cached plans become stale when that option changes, so the chosen typing policy applies consistently to subsequent planning.