From f8b340580a4bb53b10ab5824227eaf74b9e26813 Mon Sep 17 00:00:00 2001 From: John Naylor Date: Sun, 17 Jul 2022 12:33:01 +0700 Subject: [PATCH v2 4/4] Generate pg_cast function to deform tuples into structs This catalog presents no challenges for alignment padding, but has few attributes and few GETSTRUCT call sites, so is an easy PoC. --- src/backend/catalog/genbki.pl | 49 +++++++++++++++++++++++++++-- src/backend/catalog/objectaddress.c | 20 ++++++------ src/backend/parser/parse_coerce.c | 27 +++++++++------- src/include/access/htup_details.h | 6 ++++ 4 files changed, 77 insertions(+), 25 deletions(-) diff --git a/src/backend/catalog/genbki.pl b/src/backend/catalog/genbki.pl index 8ed7d1f92b..27d077bd51 100644 --- a/src/backend/catalog/genbki.pl +++ b/src/backend/catalog/genbki.pl @@ -476,16 +476,29 @@ EOM #ifndef %s_DEFORM_H #define %s_DEFORM_H +#include "access/tupmacs.h" + EOM # Emit tuple deforming function - # WIP: the same macro we had before written as a trivial function - print $deform <{columns}; my %attnames; my $attnum = 0; + my $prev_attname; + my $prev_ctype; foreach my $column (@$schema) { $attnum++; my $attname = $column->{attname}; + my $ctype = $column->{ctype}; my $atttype = $column->{atttype}; # Build hash of column names for use later @@ -546,7 +562,6 @@ GETSTRUCT { print $bki " ,\n"; } - $first = 0; print $bki " $attname = $atttype"; @@ -561,6 +576,34 @@ GETSTRUCT # Emit Anum_* constants printf $def "#define Anum_%s_%s %s\n", $catname, $attname, $attnum; + + # Emit memcpy statements with the right type lengths and tuple offsets + # WIP: one catalog at first, eventually for all of them + if ($catname eq 'pg_cast') + { + if ($first) + { + printf $deform "#define Aoff_%s_%s 0\n", $catname, $attname; + } + else + { + # current offset is the previous offset plus the previous type length, + # plus any alignment padding suitable for the current type + printf $deform "\n#define Aoff_%s_%s att_align_nominal(Aoff_%s_%s + sizeof(%s), '%s')\n", + $catname, $attname, + $catname, $prev_attname, $prev_ctype, + $types{$atttype}->{typalign}; + } + + printf $deform "\tmemcpy(&%s_struct->%s, %s_tuple + Aoff_%s_%s, sizeof(%s));\n", + $catname, $attname, + $catname, $catname, $attname, + $ctype; + } + + $first = 0; + $prev_attname = $attname; + $prev_ctype = $ctype; } print $bki "\n )\n"; diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index 4991a76c41..66e98daad1 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -3003,7 +3003,7 @@ getObjectDescription(const ObjectAddress *object, bool missing_ok) ScanKeyData skey[1]; SysScanDesc rcscan; HeapTuple tup; - Form_pg_cast castForm; + FormData_pg_cast castForm; castDesc = table_open(CastRelationId, AccessShareLock); @@ -3028,11 +3028,11 @@ getObjectDescription(const ObjectAddress *object, bool missing_ok) break; } - castForm = GETSTRUCT(pg_cast, tup); + GETSTRUCT_MEMCPY(pg_cast, &castForm, tup); appendStringInfo(&buffer, _("cast from %s to %s"), - format_type_be(castForm->castsource), - format_type_be(castForm->casttarget)); + format_type_be(castForm.castsource), + format_type_be(castForm.casttarget)); systable_endscan(rcscan); table_close(castDesc, AccessShareLock); @@ -4853,7 +4853,7 @@ getObjectIdentityParts(const ObjectAddress *object, { Relation castRel; HeapTuple tup; - Form_pg_cast castForm; + FormData_pg_cast castForm; castRel = table_open(CastRelationId, AccessShareLock); @@ -4870,16 +4870,16 @@ getObjectIdentityParts(const ObjectAddress *object, break; } - castForm = GETSTRUCT(pg_cast, tup); + GETSTRUCT_MEMCPY(pg_cast, &castForm, tup); appendStringInfo(&buffer, "(%s AS %s)", - format_type_be_qualified(castForm->castsource), - format_type_be_qualified(castForm->casttarget)); + format_type_be_qualified(castForm.castsource), + format_type_be_qualified(castForm.casttarget)); if (objname) { - *objname = list_make1(format_type_be_qualified(castForm->castsource)); - *objargs = list_make1(format_type_be_qualified(castForm->casttarget)); + *objname = list_make1(format_type_be_qualified(castForm.castsource)); + *objargs = list_make1(format_type_be_qualified(castForm.casttarget)); } table_close(castRel, AccessShareLock); diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c index 172d4b2034..0bd90fd5e8 100644 --- a/src/backend/parser/parse_coerce.c +++ b/src/backend/parser/parse_coerce.c @@ -2995,7 +2995,7 @@ bool IsBinaryCoercible(Oid srctype, Oid targettype) { HeapTuple tuple; - Form_pg_cast castForm; + FormData_pg_cast castForm; bool result; /* Fast path if same type */ @@ -3056,10 +3056,10 @@ IsBinaryCoercible(Oid srctype, Oid targettype) ObjectIdGetDatum(targettype)); if (!HeapTupleIsValid(tuple)) return false; /* no cast */ - castForm = GETSTRUCT(pg_cast, tuple); + GETSTRUCT_MEMCPY(pg_cast, &castForm, tuple); - result = (castForm->castmethod == COERCION_METHOD_BINARY && - castForm->castcontext == COERCION_CODE_IMPLICIT); + result = (castForm.castmethod == COERCION_METHOD_BINARY && + castForm.castcontext == COERCION_CODE_IMPLICIT); ReleaseSysCache(tuple); @@ -3120,11 +3120,13 @@ find_coercion_pathway(Oid targetTypeId, Oid sourceTypeId, if (HeapTupleIsValid(tuple)) { - Form_pg_cast castForm = GETSTRUCT(pg_cast, tuple); + FormData_pg_cast castForm; CoercionContext castcontext; + GETSTRUCT_MEMCPY(pg_cast, &castForm, tuple); + /* convert char value for castcontext to CoercionContext enum */ - switch (castForm->castcontext) + switch (castForm.castcontext) { case COERCION_CODE_IMPLICIT: castcontext = COERCION_IMPLICIT; @@ -3137,7 +3139,7 @@ find_coercion_pathway(Oid targetTypeId, Oid sourceTypeId, break; default: elog(ERROR, "unrecognized castcontext: %d", - (int) castForm->castcontext); + (int) castForm.castcontext); castcontext = 0; /* keep compiler quiet */ break; } @@ -3145,11 +3147,11 @@ find_coercion_pathway(Oid targetTypeId, Oid sourceTypeId, /* Rely on ordering of enum for correct behavior here */ if (ccontext >= castcontext) { - switch (castForm->castmethod) + switch (castForm.castmethod) { case COERCION_METHOD_FUNCTION: result = COERCION_PATH_FUNC; - *funcid = castForm->castfunc; + *funcid = castForm.castfunc; break; case COERCION_METHOD_INOUT: result = COERCION_PATH_COERCEVIAIO; @@ -3159,7 +3161,7 @@ find_coercion_pathway(Oid targetTypeId, Oid sourceTypeId, break; default: elog(ERROR, "unrecognized castmethod: %d", - (int) castForm->castmethod); + (int) castForm.castmethod); break; } } @@ -3287,9 +3289,10 @@ find_typmod_coercion_function(Oid typeId, if (HeapTupleIsValid(tuple)) { - Form_pg_cast castForm = GETSTRUCT(pg_cast, tuple); + FormData_pg_cast castForm; - *funcid = castForm->castfunc; + GETSTRUCT_MEMCPY(pg_cast, &castForm, tuple); + *funcid = castForm.castfunc; ReleaseSysCache(tuple); } diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h index 9d5bd76d7b..f300030504 100644 --- a/src/include/access/htup_details.h +++ b/src/include/access/htup_details.h @@ -653,6 +653,12 @@ struct MinimalTupleData */ #define GETSTRUCT(CAT, TUP) Deform_##CAT##_tuple((char *) ((TUP)->t_data) + (TUP)->t_data->t_hoff) +/* + * GETSTRUCT - given a HeapTuple pointer, deform the user data into the passed struct + */ +// WIP: The _MEMCPY suffix is a temporary scaffold to allow partial progress one catalog at a time. +#define GETSTRUCT_MEMCPY(CAT, STRUCT, TUP) Deform_##CAT##_tuple(STRUCT, (char *) ((TUP)->t_data) + (TUP)->t_data->t_hoff) + /* * Accessor macros to be used with HeapTuple pointers. */ -- 2.36.1