public inbox for [email protected]  
help / color / mirror / Atom feed
From: David Rowley <[email protected]>
To: Tom Lane <[email protected]>
Cc: Chao Li <[email protected]>
Cc: Peter Eisentraut <[email protected]>
Cc: Andres Freund <[email protected]>
Cc: Postgres hackers <[email protected]>
Subject: Re: Fix tuple deformation with virtual generated NOT NULL columns
Date: Thu, 18 Jun 2026 11:37:18 +1200
Message-ID: <CAApHDvq6FaC441C=G4Q9fNZQ-OKmaeW8yP0YjHpjyjBeWhj3+g@mail.gmail.com> (raw)
In-Reply-To: <CAApHDvpE1Jx=NrwUCihrfP+Dmkfn6kUkpCZYC10Yo+wkMu3ssQ@mail.gmail.com>
References: <[email protected]>
	<CAApHDvoQKY8zHb1LZBuYZBRszi0qVmTaV_zFup=A9xqRpJWMRQ@mail.gmail.com>
	<pse3eru75b5skbvc7jjrf7origavqojc6nqtwdrr7z6sjkyxfo@siklvj643v4f>
	<[email protected]>
	<CAApHDvogTSD_G1nkJqOvO3gZFACQUCbKg6U7yBB48r5RMaR7-Q@mail.gmail.com>
	<CAApHDvrJBXEhet4=Es_wHBKdv5PCV5OGCaJOSmJexeaFqfmUHA@mail.gmail.com>
	<[email protected]>
	<[email protected]>
	<CAApHDvpE1Jx=NrwUCihrfP+Dmkfn6kUkpCZYC10Yo+wkMu3ssQ@mail.gmail.com>

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)
 		{
 			/*


Attachments:

  [text/plain] fix_jit_deform_for_virtual_generated_cols.patch (2.6K, 2-fix_jit_deform_for_virtual_generated_cols.patch)
  download | inline diff:
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)
 		{
 			/*


view thread (22+ messages)  latest in thread

reply

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Reply to all the recipients using the --to and --cc options:
  reply via email

  To: [email protected]
  Cc: [email protected], [email protected], [email protected], [email protected], [email protected], [email protected]
  Subject: Re: Fix tuple deformation with virtual generated NOT NULL columns
  In-Reply-To: <CAApHDvq6FaC441C=G4Q9fNZQ-OKmaeW8yP0YjHpjyjBeWhj3+g@mail.gmail.com>

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox