On Thu, 18 Jun 2026 at 11:06, David Rowley <[email protected]> wrote:
> Just starting to look now, but I suspect that this code in
> llvmjit_deform.c needs to be updated now that we have virtual
> generated columns.

I've not fully processed all this code yet. I've still not worked out
why the loop that sets guaranteed_column_number doesn't break when it
finds something non-guaranteed.

Here's a draft patch I was experimenting with. It seems to fix the
issue. I need to spend more time to check it's correct.

David
diff --git a/src/backend/jit/llvm/llvmjit_deform.c 
b/src/backend/jit/llvm/llvmjit_deform.c
index 12521e3e46a..62a7e1c37fb 100644
--- a/src/backend/jit/llvm/llvmjit_deform.c
+++ b/src/backend/jit/llvm/llvmjit_deform.c
@@ -109,22 +109,27 @@ slot_compile_deform(LLVMJitContext *context, TupleDesc 
desc,
         */
        for (attnum = 0; attnum < desc->natts; attnum++)
        {
-               CompactAttribute *att = TupleDescCompactAttr(desc, attnum);
+               CompactAttribute *catt = TupleDescCompactAttr(desc, attnum);
+               Form_pg_attribute attr = TupleDescAttr(desc, attnum);
 
                /*
                 * If the column is declared NOT NULL then it must be present 
in every
                 * tuple, unless there's a "missing" entry that could provide a
-                * non-NULL value for it. That in turn guarantees that the NULL 
bitmap
-                * - if there are any NULLable columns - is at least long 
enough to
-                * cover columns up to attnum.
+                * non-NULL value for it or the column is a virtual generated 
column.
+                * That in turn guarantees that the NULL bitmap - if there are 
any
+                * NULLable columns - is at least long enough to cover columns 
up to
+                * attnum.
                 *
                 * Be paranoid and also check !attisdropped, even though the
                 * combination of attisdropped && attnotnull combination 
shouldn't
                 * exist.
                 */
-               if (att->attnullability == ATTNULLABLE_VALID &&
-                       !att->atthasmissing &&
-                       !att->attisdropped)
+               if (attr->attgenerated == ATTRIBUTE_GENERATED_VIRTUAL)
+                       break;
+
+               if (catt->attnullability == ATTNULLABLE_VALID &&
+                       !catt->atthasmissing &&
+                       !catt->attisdropped)
                        guaranteed_column_number = attnum;
        }
 
@@ -392,6 +397,8 @@ slot_compile_deform(LLVMJitContext *context, TupleDesc desc,
        for (attnum = 0; attnum < natts; attnum++)
        {
                CompactAttribute *att = TupleDescCompactAttr(desc, attnum);
+               Form_pg_attribute attr = TupleDescAttr(desc, attnum);
+
                LLVMValueRef v_incby;
                int                     alignto = att->attalignby;
                LLVMValueRef l_attno = l_int16_const(lc, attnum);
@@ -436,7 +443,8 @@ slot_compile_deform(LLVMJitContext *context, TupleDesc desc,
                 * into account, because if they're present the heaptuple's 
natts
                 * would have indicated that a slot_getmissingattrs() is needed.
                 */
-               if (att->attnullability != ATTNULLABLE_VALID)
+               if (att->attnullability != ATTNULLABLE_VALID ||
+                       attr->attgenerated == ATTRIBUTE_GENERATED_VIRTUAL)
                {
                        LLVMBasicBlockRef b_ifnotnull;
                        LLVMBasicBlockRef b_ifnull;
@@ -614,6 +622,7 @@ slot_compile_deform(LLVMJitContext *context, TupleDesc desc,
                        known_alignment += att->attlen;
                }
                else if (att->attnullability == ATTNULLABLE_VALID &&
+                                attr->attgenerated != 
ATTRIBUTE_GENERATED_VIRTUAL &&
                                 (att->attlen % alignto) == 0)
                {
                        /*

Reply via email to