Repository navigation
tursopg: parse the text in a cast to uuid - #11600
gaurav0107 wants to merge 1 commit into
Conversation
A cast to uuid was translated to CAST(x AS TEXT), so the text was kept as written. 'A0EE...'::uuid did not equal 'a0ee...'::uuid, a braced UUID printed with its braces, text that is not a UUID was accepted, and an IN (SELECT ...::uuid) on an indexed uuid column found the same row once per spelling. The cast now goes to the built-in uuid type, as a uuid column already does. Its ENCODE parses every spelling PostgreSQL accepts and its DECODE writes the value in lowercase with hyphens. A uuid column in the column list of json_to_record now gets the same parsing. Fixes tursodatabase#11475
Autofixer review🔄 Autofixer updates this comment while the review runs. Autofixer reviews pull requests from outside contributors on its own. The review of ✅ Verdict: looks good to merge. Automated review by Autofixer; maintainers decide what to merge. Autofixer started this review on its own, as it does for pull requests from outside contributors. Push a fix to get a re-review (up to 3 reviews in all); a pull request whose blocking findings stay unaddressed for 7 days is closed. Maintainers: add |
There was a problem hiding this comment.
Autofixer review of 904f27205321
What this pull request does: SELECT 'A0EEBC99-9C0B-4EF8-BB6D-6BB9BD380A11'::uuid returned the text unchanged on main, so differently written equal UUIDs compared unequal; now it returns a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11 like PostgreSQL, and 'hello'::uuid is an error.
✅ Verdict: looks good to merge.
What to do: nothing to fix; a maintainer decides whether to merge.
What the review found: No blocking problems. The description says every PostgreSQL spelling is accepted, but '{a0eebc999c0b4ef8bb6d6bb9bd380a11}'::uuid is rejected. The uuid parser shared with uuid columns also accepts urn:uuid: text that PostgreSQL rejects.
Not blocking
1 minor finding
- Minor Description says ENCODE reads every PostgreSQL spelling;
'{a0eebc999c0b4ef8bb6d6bb9bd380a11}'::uuidfails with invalid UUID value, PostgreSQL accepts it
Suggested fix: Say that braces without hyphens and hyphens after any 4-digit group are rejected, andurn:uuid:text is accepted, unlike PostgreSQL
Also wrong on main: 3 inputs this pull request doesn't fix
main gets these wrong too, so this change did not cause them.
1. Casting a valid UUID with a hyphen after any 4 digits, or braces with no hyphens, to uuid fails
Every text cast to uuid (and every insert into a uuid column) that PostgreSQL accepts but the uuid crate's Uuid::parse_str rejects fails with 'invalid UUID value': braces around 32 plain hex digits, and hyphens after any group of 4 hex digits other than the standard 8-4-4-4-12 places. The reverse case also fails: 'urn:uuid:<uuid>' is accepted, but PostgreSQL rejects it.
Input:
SELECT '{a0eebc999c0b4ef8bb6d6bb9bd380a11}'::uuid;
SELECT 'a0ee-bc99-9c0b-4ef8-bb6d-6bb9-bd38-0a11'::uuid;
SELECT 'urn:uuid:a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid;This PR:
ERROR: invalid UUID value / ERROR: invalid UUID value / a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11
main:
{a0eebc999c0b4ef8bb6d6bb9bd380a11} / a0ee-bc99-9c0b-4ef8-bb6d-6bb9-bd38-0a11 / urn:uuid:a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11 (text returned unchanged)
PostgreSQL:
a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11 / a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11 / ERROR: invalid input syntax for type uuid: "urn:uuid:a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11"
2. An invalid text cast to uuid fails with SQLSTATE P0001 instead of 22P02
| This PR | main | PostgreSQL |
|---|---|---|
ERROR: P0001: invalid UUID value |
bogus (no error) |
ERROR: 22P02: invalid input syntax for type uuid: "bogus" |
Every text cast to uuid that does not parse fails with SQLSTATE P0001 (raise_exception) and the message 'invalid UUID value'. PostgreSQL gives 22P02 and 'invalid input syntax for type uuid: "..."'. Inserting bad text into a uuid column gives the same wrong SQLSTATE.
Input:
\set VERBOSITY verbose
SELECT 'bogus'::uuid;3. Casting bytea, integer, numeric or boolean to uuid is accepted or gives the wrong error
| This PR | main | PostgreSQL |
|---|---|---|
30313233-3435-3637-3839-616263646566 / ERROR: invalid UUID value |
0123456789abcdef / 123 |
ERROR: cannot cast type bytea to uuid / ERROR: cannot cast type integer to uuid |
Every cast to uuid from a type other than text or uuid (bytea, integer, numeric, boolean) should fail with 'cannot cast type X to uuid' (SQLSTATE 42846). Instead, bytea of exactly 16 bytes becomes a uuid, and the other types fail with 'invalid UUID value'.
Input:
SELECT '0123456789abcdef'::bytea::uuid;
SELECT 123::uuid;3 other problems found outside this change
- tursopg uuid input rejects some spellings PostgreSQL accepts and accepts urn:uuid: text:
CREATE TABLE t(u uuid); INSERT INTO t VALUES ('{a0eebc999c0b4ef8bb6d6bb9bd380a11}'); INSERT INTO t VALUES ('a0ee-bc99-9c0b4ef8-bb6d-6bb9bd380a11'); INSERT INTO t VALUES ('urn:uuid:a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'); SELECT u FROM t; - tursopg: comparing a uuid or date column with a differently written string literal finds no rows:
CREATE TABLE d(x date, u uuid); INSERT INTO d VALUES ('2024-01-05', 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'); SELECT count(*) FROM d WHERE x = '2024-1-5'; SELECT count(*) FROM d WHERE u = 'A0EEBC99-9C0B-4EF8-BB6D-6BB9BD380A11'; - Casting a uuid to bytea or integer is accepted instead of failing:
SELECT 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuid::int; SELECT 'A0EEBC99-9C0B-4EF8-BB6D-6BB9BD380A11'::uuid::bytea;
Other checks: 4 refuted, 2 are findings
- Refuted:
postgres/parser/translator.rs:6527: Column path may differ: inserting uppercase or braced text into a uuid column may not normalize it
→ INSERT of uppercase and braced text into a uuid column reads back lowercase with hyphens on main and on this pull request, as in PostgreSQLtimeout 60 $b -q :memory: < /tmp/q2.sql - Refuted:
postgres/parser/translator.rs:6527: The bare name "uuid" must match the core built-in type name
→ Same literal is used by the column mapping (translator.rs:6096) and for date/time in the same match; core registersCREATE TYPE uuid; new sqltests fail if the name is wrongtimeout 1500 make -C postgres/conformance run-one FILE=pg-sqltests/select.sqltest - Refuted:
postgres/conformance/pg-sqltests/select.sqltest:333: New tests may not pass on real PostgreSQL
→ All three uuid tests pass against PostgreSQL 18; the one failure in the file is an unrelated LIKE testtimeout 900 cargo run -q --manifest-path ../../testing/sqltest/Cargo.toml --bin sqltest -- run pg-sqltests/select.sqltest --backend postgres --postgres-dsn "$PG_DSN" - Refuted:
postgres/parser/translator.rs:6527: json_to_record also uses this mapping; behavior change there
→ json_to_record(...) AS x(a uuid) now returns lowercase like PostgreSQL; main returned the uppercase texttimeout 60 $b -q :memory: < /tmp/q2.sql
Automated review by Autofixer; maintainers decide what to merge. Autofixer started this review on its own, as it does for pull requests from outside contributors. Push a fix to get a re-review (up to 3 reviews in all); a pull request whose blocking findings stay unaddressed for 7 days is closed. Maintainers: add autofixer: no-review to stop these reviews, or autofixer: review-requested to review it as requested.
Problem
In tursopg, a cast to
uuidkeeps the text as written.'A0EEBC99-9C0B-4EF8-BB6D-6BB9BD380A11'::uuid = 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'::uuidis false,CAST('{A0EE...}' AS uuid)prints the braces and the uppercase letters, and'hello'::uuidgiveshello. AnIN (SELECT ...::uuid ...)on an indexed uuid column counts the same row once for each spelling.The PostgreSQL translator turned a cast to
uuidintoCAST(x AS TEXT).Fix
A cast to
uuidnow goes to the built-inuuidtype, which is what auuidcolumn already uses. Its ENCODE (uuid_blob) reads every spelling PostgreSQL accepts (any case, braces, no hyphens) and rejects text that is not a UUID, and its DECODE writes the value in lowercase with hyphens.date,timeandtimestampcasts already work this way in the same match.The same mapping is used for the column list of
json_to_recordandjsonb_to_record, so auuidcolumn there is now parsed too, as in PostgreSQL.Not the same as PostgreSQL: text that is not a UUID fails with
invalid UUID valueand not with PostgreSQL's message and SQLSTATE 22P02.Tests
Added cases to
pg-sqltests/select.sqltestfor casting the uppercase, braced and no-hyphen forms, for an IN subquery of casts on an indexed uuid column, and for text that is not a UUID. They fail onmainand pass with this change.Fixes #11475
🤖 Opened with Superhuman, an open-source contribution agent.