-
Notifications
You must be signed in to change notification settings - Fork 3.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
builtins: automatically add builtins for each type cast #97093
Conversation
this is cool! did you also see #94859 there's one note about PG though -- if i recall correctly, in postgres each cast is implemented by calling the respective builtin function. this PR is going the other way though: each builtin function that is being added here is implemented by calling into the cast code. i'm not sure how much this distinction matters. one thing that could be related is in the pg_cast table, we should start filling out the |
that's true; ideally we make this work in the type resolution layer like pg does:
i don't recall it being easy to put this into type resolution (pls prove me wrong :D). this is also annoying as this PR will probably tie us in deeper to the
|
60991c5
to
7efa731
Compare
e378bbe
to
c764856
Compare
If you define the builtins, I wonder if the function resolution we have will work well enough. It's unlikely to work 100% consistently with Postgres until we rewrite our function/type resolution (see #75101 and ##88374 (comment)). |
based on my manual tests + my random test for casts it works good enough for now.
we'll get there one day. can't say i didn't try :P |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems fine to me but this is a a little outside my purview, would like to defer to Rafi or Marcus.
Reviewed 8 of 13 files at r1, all commit messages.
Reviewable status:complete! 0 of 0 LGTMs obtained (waiting on @otan)
pkg/internal/sqlsmith/schema.go
line 500 at r1 (raw file):
if n := tree.Name(def.Name); n.String() != def.Name { // sqlsmith doesn't seem to know how to quote these.
Whats going on here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewed 4 of 13 files at r1.
Reviewable status:complete! 0 of 0 LGTMs obtained (waiting on @cucaroach and @otan)
pkg/sql/sem/builtins/pg_builtins.go
line 200 at r1 (raw file):
} for toOID, def := range castBuiltins { n := strings.ToLower(types.OidToType[toOID].SQLString())
I don't think SQLString
works here - Postgres's naming of these functions doesn't make the SQLString naming of a type. For example, varchar
, bit
, decimal
, and char
don't seem to be functions in Postgres. It looks like they might exist, but with different names. For example bpchar
seems to work for the char
type:
marcus=# select pg_typeof('foo'::CHAR), pg_typeof(bpchar('foo'));
pg_typeof | pg_typeof
-----------+-----------
character | character
(1 row)
pkg/sql/sem/builtins/cast_test.go
line 68 at r1 (raw file):
switch typ.Oid() { case oid.T_char: return "char"
oid.T_char
represents the "char"
type, not to be confused with the CHAR
type:
marcus=# SELECT pg_typeof('foo'::CHAR), pg_typeof('foo'::"char"), pg_typeof("char"('foo'));
pg_typeof | pg_typeof | pg_typeof
-----------+-----------+-----------
character | "char" | "char"
(1 row)
So you'll want to keep the double quotes in the query, e.g., SELECT "char"(...)
instead of SELECT char(...)
. I think typ.SQLString
already includes the double quotes for this type.
Previously, mgartner (Marcus Gartner) wrote…
i think this is still right, you just need to quote the name.
|
Previously, mgartner (Marcus Gartner) wrote…
no this is right, |
Previously, otan (Oliver Tan) wrote…
ah nah good catch, had to rearrange a few things around. |
Previously, otan (Oliver Tan) wrote…
(sorry i mean, this is still the same, but bpchar / numeric was a surprise) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: can you fill in the castfunc
column of pg_cast?
Reviewable status:
complete! 0 of 0 LGTMs obtained (waiting on @cucaroach, @mgartner, and @otan)
docs/generated/sql/functions.md
line 361 at r2 (raw file):
</table> ### Cast functions
i'd actually be in favor of marking all these as hidden. what do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm, castfunc
would be "wrong" though compared to PG. is that ok?
Reviewable status:
complete! 0 of 0 LGTMs obtained (waiting on @cucaroach, @mgartner, and @rafiss)
docs/generated/sql/functions.md
line 361 at r2 (raw file):
Previously, rafiss (Rafi Shamim) wrote…
i'd actually be in favor of marking all these as hidden. what do you think?
Done.
1c53ddb
to
f20be7f
Compare
wrong in which way? you mean it would have different function OIDs? i think that's fine -- the OID would still refer to the correct function in pg_proc. |
hmm not so good for something like |
i still don't follow. what's wrong with |
ah, nvm, i see what you're getting at. |
hmm it's a little tricky because we defined casts on all oids, but the functions derived is in actuality based on the family. |
bed6dd5
to
f13beb7
Compare
(changes made + ready for another look!) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks for adding this!
Reviewable status:
complete! 0 of 0 LGTMs obtained (waiting on @cucaroach, @mgartner, and @otan)
pkg/sql/sem/builtins/fixed_oids.go
line 2048 at r6 (raw file):
2070: `crdb_internal.num_inverted_index_entries(val: tsvector, version: int) -> int`, 2072: `crdb_internal.upsert_dropped_relation_gc_ttl(desc_id: int, gc_ttl: interval) -> bool`, 2073: `box2d(geometry: geometry) -> box2d`,
just wanna confirm - so if someone adds a new type later on, they'll get an init
error telling them they need to add an entry into this fixed OID map?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
bors r=rafiss
Reviewable status:
complete! 0 of 0 LGTMs obtained (waiting on @cucaroach, @mgartner, and @rafiss)
pkg/sql/sem/builtins/fixed_oids.go
line 2048 at r6 (raw file):
Previously, rafiss (Rafi Shamim) wrote…
just wanna confirm - so if someone adds a new type later on, they'll get an
init
error telling them they need to add an entry into this fixed OID map?
yep!
👎 Rejected by code reviews |
PG adds the mask if it doesn't exist - but only on casts (not pgwire formatting). Release note (bug fix): Previously, casting an `inet` to a string type omitted the mask if a mask was not provided. This didn't match postgresql and is now resolved.
In PG, casts from one type to another can also be use the function syntax, e.g. `date(now())` = `now()::date`. This is done at type resolution time. Unfortunately we do not support that in type resolution, and from experience long ago it was tricky to do so (happy to be proven wrong). This change instead defines a builtin for each castable type, which emulates the same behavior. We already kind of do this for `oid` and `inet`, so this isn't much worse right? Release note (sql change): Each type cast is now expressable as a function, e.g. `now()::date` can be expressed as `date(now())`.
This commit correct fills in the castfunc column in pg_catalog.pg_cast now that we have all the builtins defined. Release note: None
bors r=rafiss |
Build succeeded: |
In PG, casts from one type to another can also be use the function syntax, e.g.
date(now())
=now()::date
. This is done at type resolution time.Unfortunately we do not support that in type resolution, and from experience long ago it was tricky to do so (happy to be proven wrong).
This change instead defines a builtin for each castable type, which emulates the same behavior. We already kind of do this for
oid
andinet
, so this isn't much worse right?Release note (sql change): Each type cast is now expressable as a function, e.g.
now()::date
can be expressed asdate(now())
.Resolves #97067