cockroachdb / cockroachdb/cockroach
sql: fix tuple type-checking
- Dominant language
- Go
- Stars
- 32.5k
- Forks
- 4.1k
- PR merge metrics
- PR metrics pending
Description
Our type-checking logic for comparison of tuple-typed expressions assumes that the inputs expressions are `tree.Tuple`. This is deeply flawed because there are all sorts of other expressions that are not `tree.Tuple` but have the type of tuple. Our type-checking code should never be breaking apart expressions like `tree.Tuple`. It must operate on the types of sub-expressions, not the sub-expressions themselves.
A core hurdle to get over is our overload resolution, which currently operates on `tree.Expr`, rather then `types.T` to determine the correct overload for an operator and it's input. We should be following the logic described in detail here: https://www.postgresql.org/docs/current/typeconv-oper.html
> 1. Select the operators to be considered from the pg_operator system catalog. If
> a non-schema-qualified operator name was used (the usual case), the operators
> considered are those with the matching name and argument count that are visible
> in the current search path (see Section 5.9.3). If a qualified operator name was
> given, only operators in the specified schema are considered.
>
> a. If the search path finds multiple operators with identical argument
> types, only the one appearing earliest in the path is considered. Operators
> with different argument types are considered on an equal footing regardless
> of search path position.
>
> 2. Check for an operator accepting exactly the input argument types. If one
> exists (there can be only one exact match in the set of operators considered),
> use it. Lack of an exact match creates a security hazard when calling, via
> qualified name [9] (not typical), any operator found in a schema that permits
> untrusted users to create objects. In such situations, cast arguments to force
> an exact match.
>
> a. If one argument of a binary operator invocation is of the unknown type,
> then assume it is the same type as the other argument for this check.
> Invocations involving two unknown inputs, or a prefix operator with an
> unknown input, will never find a match at this step.
>
> b. If one argument of a binary operator invocation is of the unknown type
> and the other is of a domain type, next check to see if there is an operator
> accepting exactly the domain's base type on both sides; if so, use it.
>
> 3. Look for the best match.
>
> a. Discard candidate operators for which the input types do not match and
> cannot be converted (using an implicit conversion) to match. unknown
> literals are assumed to be convertible to anything for this purpose. If only
> one candidate remains, use it; else continue to the next step.
>
> b. If any input argument is of a domain type, treat it as being of the
> domain's base type for all subsequent steps. This ensures that domains act
> like their base types for purposes of ambiguous-operator resolution.
>
> c. Run through all candidates and keep those with the most exact matches on
> input types. Keep all candidates if none have exact matches. If only one
> candidate remains, use it; else continue to the next step.
>
> d. Run through all candidates and keep those that accept preferred types (of
> the input data type's type category) at the most positions where type
> conversion will be required. Keep all candidates if none accept preferred
> types. If only one candidate remains, use it; else continue to the next
> step.
>
> e. If any input arguments are unknown, check the type categories accepted at
> those argument positions by the remaining candidates. At each position,
> select the string category if any candidate accepts that category. (This
> bias towards string is appropriate since an unknown-type literal looks like
> a string.) Otherwise, if all the remaining candidates accept the same type
> category, select that category; otherwise fail because the correct choice
> cannot be deduced without more clues. Now discard candidates that do not
> accept the selected type category. Furthermore, if any candidate accepts a
> preferred type in that category, discard candidates that accept
> non-preferred types for that argument. Keep all candidates if none survive
> these tests. If only one candidate remains, use it; else continue to the
> next step.
>
> f. If there are both unknown and known-type arguments, and all the
> known-type arguments have the same type, assume that the unknown arguments
> are also of that type, and check which candidates can accept that type at
> the unknown-argument positions. If exactly one candidate passes this test,
> use it. Otherwise, fail.
Jira issue: CRDB-25105
Contributor guide
Research direction
Start by tracing SQL comparison tuple type-checking and the overload-resolution entry point described in the issue. Compare the existing behavior with PostgreSQL's operator-resolution rules; done means resolution operates on expression types rather than splitting expressions and handles tuple-typed expressions beyond tree.Tuple.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go, sql
- Domain
- backend, databases
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 25/100