public inbox for [email protected]
help / color / mirror / Atom feed[PATCH v2] Use permanent backup-abort call back in perform_base_backup
26+ messages / 11 participants
[nested] [flat]
* [PATCH 1/2] Use permanent backup-abort call back in perform_base_backup
@ 2022-07-01 02:38 Kyotaro Horiguchi <[email protected]>
0 siblings, 0 replies; 26+ messages in thread
From: Kyotaro Horiguchi @ 2022-07-01 02:38 UTC (permalink / raw)
---
src/backend/replication/basebackup.c | 13 +++----------
1 file changed, 3 insertions(+), 10 deletions(-)
diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c
index 95440013c0..e4345dbff2 100644
--- a/src/backend/replication/basebackup.c
+++ b/src/backend/replication/basebackup.c
@@ -255,19 +255,14 @@ perform_base_backup(basebackup_options *opt, bbsink *sink)
total_checksum_failures = 0;
basebackup_progress_wait_checkpoint();
+
+ register_persistent_abort_backup_handler();
+
state.startptr = do_pg_backup_start(opt->label, opt->fastcheckpoint,
&state.starttli,
labelfile, &state.tablespaces,
tblspc_map_file);
- /*
- * Once do_pg_backup_start has been called, ensure that any failure causes
- * us to abort the backup so we don't "leak" a backup counter. For this
- * reason, *all* functionality between do_pg_backup_start() and the end of
- * do_pg_backup_stop() should be inside the error cleanup block!
- */
-
- PG_ENSURE_ERROR_CLEANUP(do_pg_abort_backup, BoolGetDatum(false));
{
ListCell *lc;
tablespaceinfo *ti;
@@ -375,8 +370,6 @@ perform_base_backup(basebackup_options *opt, bbsink *sink)
basebackup_progress_wait_wal_archive(&state);
endptr = do_pg_backup_stop(labelfile->data, !opt->nowait, &endtli);
}
- PG_END_ENSURE_ERROR_CLEANUP(do_pg_abort_backup, BoolGetDatum(false));
-
if (opt->includewal)
{
--
2.31.1
----Next_Part(Fri_Jul__1_11_46_53_2022_957)--
Content-Type: Text/X-Patch; charset=us-ascii
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
filename="0002-Remove-extra-code-block.patch"
^ permalink raw reply [nested|flat] 26+ messages in thread
* [PATCH v2] Use permanent backup-abort call back in perform_base_backup
@ 2022-07-01 02:38 Kyotaro Horiguchi <[email protected]>
0 siblings, 0 replies; 26+ messages in thread
From: Kyotaro Horiguchi @ 2022-07-01 02:38 UTC (permalink / raw)
---
src/backend/replication/basebackup.c | 23 +++++++++++++----------
1 file changed, 13 insertions(+), 10 deletions(-)
diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c
index 95440013c0..6f8fb78212 100644
--- a/src/backend/replication/basebackup.c
+++ b/src/backend/replication/basebackup.c
@@ -234,6 +234,11 @@ perform_base_backup(basebackup_options *opt, bbsink *sink)
StringInfo tblspc_map_file;
backup_manifest_info manifest;
+ if (get_backup_status() == SESSION_BACKUP_RUNNING)
+ ereport(ERROR,
+ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ errmsg("a backup is already in progress in this session")));
+
/* Initial backup state, insofar as we know it now. */
state.tablespaces = NIL;
state.tablespace_num = 0;
@@ -255,19 +260,15 @@ perform_base_backup(basebackup_options *opt, bbsink *sink)
total_checksum_failures = 0;
basebackup_progress_wait_checkpoint();
+
+ register_persistent_abort_backup_handler();
+
state.startptr = do_pg_backup_start(opt->label, opt->fastcheckpoint,
&state.starttli,
labelfile, &state.tablespaces,
tblspc_map_file);
- /*
- * Once do_pg_backup_start has been called, ensure that any failure causes
- * us to abort the backup so we don't "leak" a backup counter. For this
- * reason, *all* functionality between do_pg_backup_start() and the end of
- * do_pg_backup_stop() should be inside the error cleanup block!
- */
-
- PG_ENSURE_ERROR_CLEANUP(do_pg_abort_backup, BoolGetDatum(false));
+ PG_TRY();
{
ListCell *lc;
tablespaceinfo *ti;
@@ -373,10 +374,12 @@ perform_base_backup(basebackup_options *opt, bbsink *sink)
}
basebackup_progress_wait_wal_archive(&state);
+ }
+ PG_FINALLY();
+ {
endptr = do_pg_backup_stop(labelfile->data, !opt->nowait, &endtli);
}
- PG_END_ENSURE_ERROR_CLEANUP(do_pg_abort_backup, BoolGetDatum(false));
-
+ PG_END_TRY();
if (opt->includewal)
{
--
2.31.1
----Next_Part(Fri_Jul__1_12_05_37_2022_535)----
^ permalink raw reply [nested|flat] 26+ messages in thread
* Re: Extract numeric filed in JSONB more effectively
@ 2023-08-02 06:01 jian he <[email protected]>
2023-08-03 00:50 ` Re: Extract numeric filed in JSONB more effectively Andy Fan <[email protected]>
0 siblings, 1 reply; 26+ messages in thread
From: jian he @ 2023-08-02 06:01 UTC (permalink / raw)
To: Andy Fan <[email protected]>; +Cc: pgsql-hackers
On Tue, Aug 1, 2023 at 12:39 PM Andy Fan <[email protected]> wrote:
>
> Hi:
>
> Currently if we want to extract a numeric field in jsonb, we need to use
> the following expression: cast (a->>'a' as numeric). It will turn a numeric
> to text first and then turn the text to numeric again. See
> jsonb_object_field_text and JsonbValueAsText. However the binary format
> of numeric in JSONB is compatible with the numeric in SQL, so I think we
> can have an operator to extract the numeric directly. If the value of a given
> field is not a numeric data type, an error will be raised, this can be
> documented.
>
> In this patch, I added a new operator for this purpose, here is the
> performance gain because of this.
>
> create table tb (a jsonb);
> insert into tb select '{"a": 1}'::jsonb from generate_series(1, 100000)i;
>
> current method:
> select count(*) from tb where cast (a->>'a' as numeric) = 2;
> 167ms.
>
> new method:
> select count(*) from tb where a@->'a' = 2;
> 65ms.
>
> Is this the right way to go? Testcase, document and catalog version are
> updated.
>
>
> --
> Best Regards
> Andy Fan
return PointerGetDatum(v->val.numeric);
should be something like
PG_RETURN_NUMERIC(v->val.numeric);
?
^ permalink raw reply [nested|flat] 26+ messages in thread
* Re: Extract numeric filed in JSONB more effectively
2023-08-02 06:01 Re: Extract numeric filed in JSONB more effectively jian he <[email protected]>
@ 2023-08-03 00:50 ` Andy Fan <[email protected]>
2023-08-03 04:59 ` Re: Extract numeric filed in JSONB more effectively Pavel Stehule <[email protected]>
0 siblings, 1 reply; 26+ messages in thread
From: Andy Fan @ 2023-08-03 00:50 UTC (permalink / raw)
To: jian he <[email protected]>; +Cc: pgsql-hackers
Hi Jian:
> return PointerGetDatum(v->val.numeric);
> should be something like
> PG_RETURN_NUMERIC(v->val.numeric);
> ?
>
Thanks for this reminder, a new patch is attached. and commitfest
entry is added as well[1]. For recording purposes, I compared the
new operator with all the existing operators.
select 1 from tb where (a->'a')::numeric = 2; 30.56ms
select 1 from tb where (a->>'a')::numeric = 2; 29.43ms
select 1 from tb where (a@->'a') = 2; 14.80ms
[1] https://commitfest.postgresql.org/44/4476/
--
Best Regards
Andy Fan
Attachments:
[application/octet-stream] v2-0001-Add-jsonb-operator-to-return-a-numeric-directly.patch (5.7K, ../../CAKU4AWrap1zpYqunJwWTN=CdP7E8e0U4mYmwn7hvTW3ERuENVg@mail.gmail.com/3-v2-0001-Add-jsonb-operator-to-return-a-numeric-directly.patch)
download | inline diff:
From 1415e09d6ca860d466939229e6d6a9012bf2bbcf Mon Sep 17 00:00:00 2001
From: Andy Fan <[email protected]>
Date: Tue, 1 Aug 2023 10:38:29 +0800
Subject: [PATCH v1] Add jsonb operator to return a numeric directly.
The binary format of numeric in JOSNB is compatible with the numeric
in SQL, so we can get the numeric more effectively.
---
doc/src/sgml/func.sgml | 14 +++++++++++
src/backend/utils/adt/jsonfuncs.c | 26 ++++++++++++++++++++
src/include/catalog/catversion.h | 2 +-
src/include/catalog/pg_operator.dat | 3 +++
src/include/catalog/pg_proc.dat | 4 +++
src/test/regress/expected/jsonb_jsonpath.out | 20 +++++++++++++++
src/test/regress/sql/jsonb_jsonpath.sql | 4 +++
7 files changed, 72 insertions(+), 1 deletion(-)
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index be2f54c9141..7f4b8970475 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -15699,6 +15699,20 @@ table2-mapping
<returnvalue>t</returnvalue>
</para></entry>
</row>
+ <row>
+ <entry role="func_table_entry"><para role="func_signature">
+ <type>jsonb</type> <literal>@-></literal> <type>jsonpath</type>
+ <returnvalue>numeric</returnvalue>
+ </para>
+ <para>
+ Returns the result of a JSON value at the specified path as numeric.
+ Raise error if the JSON value is not a numeric.
+ </para>
+ <para>
+ <literal>'{"a":1}'::jsonb @-> 'a' </literal>
+ <returnvalue>1</returnvalue>
+ </para></entry>
+ </row>
</tbody>
</tgroup>
</table>
diff --git a/src/backend/utils/adt/jsonfuncs.c b/src/backend/utils/adt/jsonfuncs.c
index a4bfa5e4040..5393df0ed7f 100644
--- a/src/backend/utils/adt/jsonfuncs.c
+++ b/src/backend/utils/adt/jsonfuncs.c
@@ -886,6 +886,32 @@ json_object_field_text(PG_FUNCTION_ARGS)
PG_RETURN_NULL();
}
+Datum
+jsonb_object_field_numeric(PG_FUNCTION_ARGS)
+{
+ Jsonb *jb = PG_GETARG_JSONB_P(0);
+ text *key = PG_GETARG_TEXT_PP(1);
+ JsonbValue *v;
+ JsonbValue vbuf;
+
+ if (!JB_ROOT_IS_OBJECT(jb))
+ PG_RETURN_NULL();
+
+ v = getKeyJsonValueFromContainer(&jb->root,
+ VARDATA_ANY(key),
+ VARSIZE_ANY_EXHDR(key),
+ &vbuf);
+
+ if (v == NULL || v->type == jbvNull)
+ PG_RETURN_NULL();
+
+ if (v->type != jbvNumeric)
+ elog(ERROR, "field '%s' has non-numeric value.", text_to_cstring(key));
+
+ return PointerGetDatum(v->val.numeric);
+};
+
+
Datum
jsonb_object_field_text(PG_FUNCTION_ARGS)
{
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index f507b49bb28..5a534771edb 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -57,6 +57,6 @@
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 202307261
+#define CATALOG_VERSION_NO 202308011
#endif
diff --git a/src/include/catalog/pg_operator.dat b/src/include/catalog/pg_operator.dat
index b2cdea66c4b..d63b9f5188d 100644
--- a/src/include/catalog/pg_operator.dat
+++ b/src/include/catalog/pg_operator.dat
@@ -3178,6 +3178,9 @@
{ oid => '3477', descr => 'get jsonb object field as text',
oprname => '->>', oprleft => 'jsonb', oprright => 'text', oprresult => 'text',
oprcode => 'jsonb_object_field_text' },
+{ oid => '3814', descr => 'get jsonb object field as numeric',
+ oprname => '@->', oprleft => 'jsonb', oprright => 'text', oprresult => 'numeric',
+ oprcode => 'jsonb_object_field_numeric' },
{ oid => '3212', descr => 'get jsonb array element',
oprname => '->', oprleft => 'jsonb', oprright => 'int4', oprresult => 'jsonb',
oprcode => 'jsonb_array_element' },
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 6996073989a..e93303f3be7 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -9928,6 +9928,10 @@
proname => 'jsonb_object_field_text', prorettype => 'text',
proargtypes => 'jsonb text', proargnames => '{from_json, field_name}',
prosrc => 'jsonb_object_field_text' },
+{ oid => '3813',
+ proname => 'jsonb_object_field_numeric', prorettype => 'numeric',
+ proargtypes => 'jsonb text', proargnames => '{from_json, field_name}',
+ prosrc => 'jsonb_object_field_numeric' },
{ oid => '3215',
proname => 'jsonb_array_element', prorettype => 'jsonb',
proargtypes => 'jsonb int4', proargnames => '{from_json, element_index}',
diff --git a/src/test/regress/expected/jsonb_jsonpath.out b/src/test/regress/expected/jsonb_jsonpath.out
index 6659bc9091a..bf2351cf9cf 100644
--- a/src/test/regress/expected/jsonb_jsonpath.out
+++ b/src/test/regress/expected/jsonb_jsonpath.out
@@ -34,6 +34,26 @@ select jsonb '{"a": 12}' @? '$.b + 2';
(1 row)
+select jsonb '{"a": 12}' @-> 'a';
+ ?column?
+----------
+ 12
+(1 row)
+
+select pg_typeof(jsonb '{"a": 12}' @-> 'a');
+ pg_typeof
+-----------
+ numeric
+(1 row)
+
+select jsonb '{"a": 12}' @-> 'b';
+ ?column?
+----------
+
+(1 row)
+
+select jsonb '{"a": "12a"}' @-> 'a';
+ERROR: field 'a' has non-numeric value.
select jsonb '{"a": {"a": 12}}' @? '$.a.a';
?column?
----------
diff --git a/src/test/regress/sql/jsonb_jsonpath.sql b/src/test/regress/sql/jsonb_jsonpath.sql
index e0ce509264a..32576566f11 100644
--- a/src/test/regress/sql/jsonb_jsonpath.sql
+++ b/src/test/regress/sql/jsonb_jsonpath.sql
@@ -4,6 +4,10 @@ select jsonb '{"a": 12}' @? '$.a.b';
select jsonb '{"a": 12}' @? '$.b';
select jsonb '{"a": 12}' @? '$.a + 2';
select jsonb '{"a": 12}' @? '$.b + 2';
+select jsonb '{"a": 12}' @-> 'a';
+select pg_typeof(jsonb '{"a": 12}' @-> 'a');
+select jsonb '{"a": 12}' @-> 'b';
+select jsonb '{"a": "12a"}' @-> 'a';
select jsonb '{"a": {"a": 12}}' @? '$.a.a';
select jsonb '{"a": {"a": 12}}' @? '$.*.a';
select jsonb '{"b": {"a": 12}}' @? '$.*.a';
--
2.21.0
^ permalink raw reply [nested|flat] 26+ messages in thread
* Re: Extract numeric filed in JSONB more effectively
2023-08-02 06:01 Re: Extract numeric filed in JSONB more effectively jian he <[email protected]>
2023-08-03 00:50 ` Re: Extract numeric filed in JSONB more effectively Andy Fan <[email protected]>
@ 2023-08-03 04:59 ` Pavel Stehule <[email protected]>
2023-08-03 07:53 ` Re: Extract numeric filed in JSONB more effectively Andy Fan <[email protected]>
0 siblings, 1 reply; 26+ messages in thread
From: Pavel Stehule @ 2023-08-03 04:59 UTC (permalink / raw)
To: Andy Fan <[email protected]>; +Cc: jian he <[email protected]>; pgsql-hackers
Hi
čt 3. 8. 2023 v 2:51 odesílatel Andy Fan <[email protected]> napsal:
> Hi Jian:
>
>
>> return PointerGetDatum(v->val.numeric);
>> should be something like
>> PG_RETURN_NUMERIC(v->val.numeric);
>> ?
>>
>
> Thanks for this reminder, a new patch is attached. and commitfest
> entry is added as well[1]. For recording purposes, I compared the
> new operator with all the existing operators.
>
> select 1 from tb where (a->'a')::numeric = 2; 30.56ms
> select 1 from tb where (a->>'a')::numeric = 2; 29.43ms
> select 1 from tb where (a@->'a') = 2; 14.80ms
>
> [1] https://commitfest.postgresql.org/44/4476/
>
>
I don't like this solution because it is bloating operators and it is not
extra readable. For completeness you should implement cast for date, int,
boolean too. Next, the same problem is with XML or hstore type (probably
with any types that are containers).
It is strange so only casting is 2x slower. I don't like the idea so using
a special operator is 2x faster than common syntax for casting. It is a
signal, so there is a space for optimization. Black magic with special
operators is not user friendly for relatively common problems.
Maybe we can introduce some *internal operator* "extract to type", and in
rewrite stage we can the pattern (x->'field')::type transform to OP(x,
'field', typid)
Regards
Pavel
--
> Best Regards
> Andy Fan
>
^ permalink raw reply [nested|flat] 26+ messages in thread
* Re: Extract numeric filed in JSONB more effectively
2023-08-02 06:01 Re: Extract numeric filed in JSONB more effectively jian he <[email protected]>
2023-08-03 00:50 ` Re: Extract numeric filed in JSONB more effectively Andy Fan <[email protected]>
2023-08-03 04:59 ` Re: Extract numeric filed in JSONB more effectively Pavel Stehule <[email protected]>
@ 2023-08-03 07:53 ` Andy Fan <[email protected]>
2023-08-03 09:47 ` Re: Extract numeric filed in JSONB more effectively Pavel Stehule <[email protected]>
2023-08-03 12:34 ` Re: Extract numeric filed in JSONB more effectively Chapman Flack <[email protected]>
0 siblings, 2 replies; 26+ messages in thread
From: Andy Fan @ 2023-08-03 07:53 UTC (permalink / raw)
To: Pavel Stehule <[email protected]>; +Cc: jian he <[email protected]>; pgsql-hackers
Hi Pavel:
Thanks for the feedback.
I don't like this solution because it is bloating operators and it is not
> extra readable.
>
If we support it with cast, could we say we are bloating CAST? It is true
that it is not extra readable, if so how about a->>'a' return text?
Actually
I can't guess any meaning of the existing jsonb operations without
documentation.
For completeness you should implement cast for date, int, boolean too.
> Next, the same problem is with XML or hstore type (probably with any types
> that are containers).
>
I am not sure completeness is a gold rule we should obey anytime,
like we have some function like int24le to avoid the unnecessary
cast, but we just avoid casting for special types for performance
reason, but not for all. At the same time, `int2/int4/int8` doesn't
have a binary compatibility type in jsonb. and the serialization
/deserialization for boolean is pretty cheap.
I didn't realize timetime types are binary compatible with SQL,
so maybe we can have some similar optimization as well.
(It is a pity that timestamp(tz) are not binary, or else we may
just need one operator).
>
> I don't like the idea so using a special operator is 2x faster than common
> syntax for casting. It is a signal, so there is a space for optimization.
> Black magic with special operators is not user friendly for relatively
> common problems.
>
I don't think "Black magic" is a proper word here, since it is not much
different from ->> return a text. If you argue text can be cast to
most-of-types, that would be a reason, but I doubt this difference
should generate a "black magic".
>
> Maybe we can introduce some *internal operator* "extract to type", and in
> rewrite stage we can the pattern (x->'field')::type transform to OP(x,
> 'field', typid)
>
Not sure what the OP should be? If it is a function, what is the
return value? It looks to me like it is hard to do in c language?
After all, if we really care about the number of operators, I'm OK
with just let users use the function directly, like
jsonb_field_as_numeric(jsonb, 'filedname')
jsonb_field_as_timestamp(jsonb, 'filedname');
jsonb_field_as_timestamptz(jsonb, 'filedname');
jsonb_field_as_date(jsonb, 'filedname');
it can save an operator and sloves the readable issue.
--
Best Regards
Andy Fan
^ permalink raw reply [nested|flat] 26+ messages in thread
* Re: Extract numeric filed in JSONB more effectively
2023-08-02 06:01 Re: Extract numeric filed in JSONB more effectively jian he <[email protected]>
2023-08-03 00:50 ` Re: Extract numeric filed in JSONB more effectively Andy Fan <[email protected]>
2023-08-03 04:59 ` Re: Extract numeric filed in JSONB more effectively Pavel Stehule <[email protected]>
2023-08-03 07:53 ` Re: Extract numeric filed in JSONB more effectively Andy Fan <[email protected]>
@ 2023-08-03 09:47 ` Pavel Stehule <[email protected]>
2023-08-03 13:22 ` Re: Extract numeric filed in JSONB more effectively Andy Fan <[email protected]>
1 sibling, 1 reply; 26+ messages in thread
From: Pavel Stehule @ 2023-08-03 09:47 UTC (permalink / raw)
To: Andy Fan <[email protected]>; +Cc: jian he <[email protected]>; pgsql-hackers
Hi
čt 3. 8. 2023 v 9:53 odesílatel Andy Fan <[email protected]> napsal:
> Hi Pavel:
>
> Thanks for the feedback.
>
> I don't like this solution because it is bloating operators and it is not
>> extra readable.
>>
>
> If we support it with cast, could we say we are bloating CAST? It is true
> that it is not extra readable, if so how about a->>'a' return text?
> Actually
> I can't guess any meaning of the existing jsonb operations without
> documentation.
>
yes, it can bloat CAST, but for usage we have already used syntax, and
these casts are cooked already:
(2023-08-03 11:04:51) postgres=# select castfunc::regprocedure from pg_cast
where castsource = 'jsonb'::regtype;
┌──────────────────┐
│ castfunc │
╞══════════════════╡
│ - │
│ bool(jsonb) │
│ "numeric"(jsonb) │
│ int2(jsonb) │
│ int4(jsonb) │
│ int8(jsonb) │
│ float4(jsonb) │
│ float8(jsonb) │
└──────────────────┘
(8 rows)
the operator ->> was a special case, the text type is special in postgres
as the most convertible type. And when you want to visualise a value or
display the value, you should convert value to text.
I can live with that because it is just one, but with your proposal opening
the doors for implementing tens of similar operators, I think it is bad.
Using ::target_type is common syntax and doesn't require reading
documentation.
More, I believe so lot of people uses more common syntax, and then this
syntax should to have good performance - for jsonb - (val->'op')::numeric
works, and then there should not be performance penalty, because this
syntax will be used in 99%.
Usage of cast is self documented.
> For completeness you should implement cast for date, int, boolean too.
>> Next, the same problem is with XML or hstore type (probably with any types
>> that are containers).
>>
>
> I am not sure completeness is a gold rule we should obey anytime,
> like we have some function like int24le to avoid the unnecessary
> cast, but we just avoid casting for special types for performance
> reason, but not for all. At the same time, `int2/int4/int8` doesn't
> have a binary compatibility type in jsonb. and the serialization
> /deserialization for boolean is pretty cheap.
>
> I didn't realize timetime types are binary compatible with SQL,
> so maybe we can have some similar optimization as well.
> (It is a pity that timestamp(tz) are not binary, or else we may
> just need one operator).
>
>
>>
>> I don't like the idea so using a special operator is 2x faster than
>> common syntax for casting. It is a signal, so there is a space for
>> optimization. Black magic with special operators is not user friendly for
>> relatively common problems.
>>
>
> I don't think "Black magic" is a proper word here, since it is not much
> different from ->> return a text. If you argue text can be cast to
> most-of-types, that would be a reason, but I doubt this difference
> should generate a "black magic".
>
I used the term black magic, because nobody without reading documentation
can find this operator. It is used just for this special case, and the
functionality is the same as using cast (only with different performance).
The operator ->> is more widely used. But if we have some possibility to
work without it, then the usage for a lot of users will be more simple.
More if the target types can be based on context
Can be nice to use some like `EXTRACT(YEAR FROM val->'field')` instead
`EXTRACT(YEAR FROM (val->>'field')::date)`
>
>>
>> Maybe we can introduce some *internal operator* "extract to type", and in
>> rewrite stage we can the pattern (x->'field')::type transform to OP(x,
>> 'field', typid)
>>
>
> Not sure what the OP should be? If it is a function, what is the
> return value? It looks to me like it is hard to do in c language?
>
It should be internal structure - it can be similar like COALESCE or IS
operator
>
> After all, if we really care about the number of operators, I'm OK
> with just let users use the function directly, like
>
> jsonb_field_as_numeric(jsonb, 'filedname')
> jsonb_field_as_timestamp(jsonb, 'filedname');
> jsonb_field_as_timestamptz(jsonb, 'filedname');
> jsonb_field_as_date(jsonb, 'filedname');
>
> it can save an operator and sloves the readable issue.
>
I don't like it too much, but it is better than introduction new operator
We already have the jsonb_extract_path and jsonb_extract_path_text
function.
I can imagine to usage "anyelement" type too. some like
`jsonb_extract_path_type(jsonb, anyelement, variadic text[] )`
> --
> Best Regards
> Andy Fan
>
^ permalink raw reply [nested|flat] 26+ messages in thread
* Re: Extract numeric filed in JSONB more effectively
2023-08-02 06:01 Re: Extract numeric filed in JSONB more effectively jian he <[email protected]>
2023-08-03 00:50 ` Re: Extract numeric filed in JSONB more effectively Andy Fan <[email protected]>
2023-08-03 04:59 ` Re: Extract numeric filed in JSONB more effectively Pavel Stehule <[email protected]>
2023-08-03 07:53 ` Re: Extract numeric filed in JSONB more effectively Andy Fan <[email protected]>
2023-08-03 09:47 ` Re: Extract numeric filed in JSONB more effectively Pavel Stehule <[email protected]>
@ 2023-08-03 13:22 ` Andy Fan <[email protected]>
0 siblings, 0 replies; 26+ messages in thread
From: Andy Fan @ 2023-08-03 13:22 UTC (permalink / raw)
To: Pavel Stehule <[email protected]>; +Cc: jian he <[email protected]>; pgsql-hackers
Hi:
> More, I believe so lot of people uses more common syntax, and then this
> syntax should to have good performance - for jsonb - (val->'op')::numeric
> works, and then there should not be performance penalty, because this
> syntax will be used in 99%.
>
This looks like a valid opinion IMO, but to rescue it, we have to do
something like "internal structure" and remove the existing cast.
But even we pay the effort, it still breaks some common knowledge,
since xx:numeric is not a cast. It is an "internal structure"!
I don't think "Black magic" is a proper word here, since it is not much
>> different from ->> return a text. If you argue text can be cast to
>> most-of-types, that would be a reason, but I doubt this difference
>> should generate a "black magic".
>>
>
> I used the term black magic, because nobody without reading documentation
> can find this operator.
>
I think this is what document is used for..
> It is used just for this special case, and the functionality is the same
> as using cast (only with different performance).
>
This is not good, but I didn't see a better choice so far, see my first
graph.
>
> The operator ->> is more widely used. But if we have some possibility to
> work without it, then the usage for a lot of users will be more simple.
> More if the target types can be based on context
>
It would be cool but still I didn't see a way to do that without making
something else complex.
>>> Maybe we can introduce some *internal operator* "extract to type", and
>>> in rewrite stage we can the pattern (x->'field')::type transform to OP(x,
>>> 'field', typid)
>>>
>>
>> Not sure what the OP should be? If it is a function, what is the
>> return value? It looks to me like it is hard to do in c language?
>>
>
> It should be internal structure - it can be similar like COALESCE or IS
> operator
>
It may work, but see my answer in the first graph.
>
>
>>
>> After all, if we really care about the number of operators, I'm OK
>> with just let users use the function directly, like
>>
>> jsonb_field_as_numeric(jsonb, 'filedname')
>> jsonb_field_as_timestamp(jsonb, 'filedname');
>> jsonb_field_as_timestamptz(jsonb, 'filedname');
>> jsonb_field_as_date(jsonb, 'filedname');
>>
>> it can save an operator and sloves the readable issue.
>>
>
> I don't like it too much, but it is better than introduction new operator
>
Good to know it. Naming operators is a complex task if we add four.
> We already have the jsonb_extract_path and jsonb_extract_path_text
> function.
>
I can't follow this. jsonb_extract_path returns a jsonb, which is far
away from
our goal: return a numeric effectively?
I can imagine to usage "anyelement" type too. some like
> `jsonb_extract_path_type(jsonb, anyelement, variadic text[] )`
>
Can you elaborate this please?
--
Best Regards
Andy Fan
^ permalink raw reply [nested|flat] 26+ messages in thread
* Re: Extract numeric filed in JSONB more effectively
2023-08-02 06:01 Re: Extract numeric filed in JSONB more effectively jian he <[email protected]>
2023-08-03 00:50 ` Re: Extract numeric filed in JSONB more effectively Andy Fan <[email protected]>
2023-08-03 04:59 ` Re: Extract numeric filed in JSONB more effectively Pavel Stehule <[email protected]>
2023-08-03 07:53 ` Re: Extract numeric filed in JSONB more effectively Andy Fan <[email protected]>
@ 2023-08-03 12:34 ` Chapman Flack <[email protected]>
2023-08-03 13:50 ` Re: Extract numeric filed in JSONB more effectively Andy Fan <[email protected]>
1 sibling, 1 reply; 26+ messages in thread
From: Chapman Flack @ 2023-08-03 12:34 UTC (permalink / raw)
To: Andy Fan <[email protected]>; +Cc: Pavel Stehule <[email protected]>; jian he <[email protected]>; pgsql-hackers
On 2023-08-03 03:53, Andy Fan wrote:
> I didn't realize timetime types are binary compatible with SQL,
> so maybe we can have some similar optimization as well.
> (It is a pity that timestamp(tz) are not binary, or else we may
> just need one operator).
Not to veer from the thread, but something about that paragraph
has been hard for me to parse/follow.
>> Maybe we can introduce some *internal operator* "extract to type", and
>> in
>> rewrite stage we can the pattern (x->'field')::type transform to OP(x,
>> 'field', typid)
>
> Not sure what the OP should be? If it is a function, what is the
> return value? It looks to me like it is hard to do in c language?
Now I am wondering about the 'planner support function' available
in CREATE FUNCTION since PG 12. I've never played with that yet.
Would that make it possible to have some, rather generic, extract
from JSON operator that can look at the surrounding expression
and replace itself sometimes with something more efficient?
Regards,
-Chap
^ permalink raw reply [nested|flat] 26+ messages in thread
* Re: Extract numeric filed in JSONB more effectively
2023-08-02 06:01 Re: Extract numeric filed in JSONB more effectively jian he <[email protected]>
2023-08-03 00:50 ` Re: Extract numeric filed in JSONB more effectively Andy Fan <[email protected]>
2023-08-03 04:59 ` Re: Extract numeric filed in JSONB more effectively Pavel Stehule <[email protected]>
2023-08-03 07:53 ` Re: Extract numeric filed in JSONB more effectively Andy Fan <[email protected]>
2023-08-03 12:34 ` Re: Extract numeric filed in JSONB more effectively Chapman Flack <[email protected]>
@ 2023-08-03 13:50 ` Andy Fan <[email protected]>
0 siblings, 0 replies; 26+ messages in thread
From: Andy Fan @ 2023-08-03 13:50 UTC (permalink / raw)
To: Chapman Flack <[email protected]>; +Cc: Pavel Stehule <[email protected]>; jian he <[email protected]>; pgsql-hackers
Hi:
On Thu, Aug 3, 2023 at 8:34 PM Chapman Flack <[email protected]> wrote:
> On 2023-08-03 03:53, Andy Fan wrote:
> > I didn't realize timetime types are binary compatible with SQL,
> > so maybe we can have some similar optimization as well.
> > (It is a pity that timestamp(tz) are not binary, or else we may
> > just need one operator).
>
> Not to veer from the thread, but something about that paragraph
> has been hard for me to parse/follow.
>
I don't think this is a key conflict so far. but I'd explain this in more
detail. If timestamp -> timestamptz or timestamptz -> timestamp is
binary compatible, we can only have 1 operator to return a timestamp.
then when we cast it to timestamptz, it will be a no-op during runtime.
however cast between timestamp and timestamptz is not binary
compatible. whose castmethod is 'f';
>
> >> Maybe we can introduce some *internal operator* "extract to type", and
> >> in
> >> rewrite stage we can the pattern (x->'field')::type transform to OP(x,
> >> 'field', typid)
> >
> > Not sure what the OP should be? If it is a function, what is the
> > return value? It looks to me like it is hard to do in c language?
>
> Now I am wondering about the 'planner support function' available
> in CREATE FUNCTION since PG 12. I've never played with that yet.
> Would that make it possible to have some, rather generic, extract
> from JSON operator that can look at the surrounding expression
> and replace itself sometimes with something efficient?
>
I didn't realize this before, 'planner support function' looks
amazing and SupportRequestSimplify looks promising, I will check it
more.
--
Best Regards
Andy Fan
^ permalink raw reply [nested|flat] 26+ messages in thread
* Re: Change copyObject() to use typeof_unqual
@ 2026-03-06 19:17 Peter Eisentraut <[email protected]>
2026-03-07 00:17 ` Re: Change copyObject() to use typeof_unqual Jelte Fennema-Nio <[email protected]>
2026-06-13 12:14 ` Re: Change copyObject() to use typeof_unqual Álvaro Herrera <[email protected]>
0 siblings, 2 replies; 26+ messages in thread
From: Peter Eisentraut @ 2026-03-06 19:17 UTC (permalink / raw)
To: pgsql-hackers; +Cc: Jelte Fennema-Nio <[email protected]>
On 04.02.26 11:46, Peter Eisentraut wrote:
> On 20.01.26 10:37, Peter Eisentraut wrote:
>> Currently, when the argument of copyObject() is const-qualified, the
>> return type is also, because the use of typeof carries over all the
>> qualifiers. This is incorrect, since the point of copyObject() is to
>> make a copy to mutate. But apparently no code ran into it.
>>
>> The new implementation uses typeof_unqual, which drops the qualifiers,
>> making this work correctly.
>>
>> typeof_unqual is standardized in C23, but all recent versions of all
>> the usual compilers support it even in non-C23 mode, at least as
>> __typeof_unqual__. We add a configure/meson test for typeof_unqual
>> and __typeof_unqual__ and use it if it's available, else we use the
>> existing fallback of just returning void *.
>
> I committed this first part, but it ran into some trouble on the buildfarm:
>
> https://buildfarm.postgresql.org/cgi-bin/show_log.pl?
> nm=taipan&dt=2026-02-04%2008%3A39%3A34
>
> The problem is that configure detected that gcc supports typeof_unqual,
> but the clang used to produce the .bc files does not.
Here is a new version, after the previous one was reverted.
This is rebased over commit 1887d822f14 and now also provides a C++
implementation, corresponding to the C++ typeof implementation added by
that commit.
This revealed an insufficiency in that commit, which I fix in the first
patch.
I have addressed the above problem by swapping the order of the probes
(putting the underscore variant first), as discussed.
There was also an issue that newer MSVC versions claimed to support
typeof_unqual but it didn't work correctly. I have enhanced the
configure probes to detect this problem.
From f2f750f7c3ab6b73514ab2fd5f02185abe9ad59f Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <[email protected]>
Date: Fri, 6 Mar 2026 13:31:01 +0100
Subject: [PATCH v2 1/3] Fixes for C++ typeof implementation
This fixes two bugs in commit 1887d822f14.
First, if we are using the fallback C++ implementation of typeof, then
we need to include the C++ header <type_traits> for
std::remove_reference_t. This header is also likely to be used for
other C++ implementations of type tricks, so we'll put it into the
global includes.
Second, for the case that the C compiler supports typeof in a spelling
that is not "typeof" (for example, __typeof__), then we need to #undef
typeof in the C++ section to avoid warnings about duplicate macro
definitions.
---
src/include/c.h | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/src/include/c.h b/src/include/c.h
index f66c752d4a0..5b678283469 100644
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -82,6 +82,14 @@
#endif
#ifdef ENABLE_NLS
#include <libintl.h>
+#endif
+
+#ifdef __cplusplus
+extern "C++"
+{
+/* This header is used in the definition of various C++ things below. */
+#include <type_traits>
+}
#endif
/* Pull in fundamental symbols that we also expose to applications */
@@ -435,6 +443,7 @@
* [1]: https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2927.htm#existing-decltype
*/
#if defined(__cplusplus)
+#undef typeof
#ifdef pg_cxx_typeof
#define typeof(x) pg_cxx_typeof(x)
#elif !defined(HAVE_CXX_TYPEOF)
--
2.53.0
From d57d96e3929cd7ef2484e9d3ac95b1c9ba774823 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <[email protected]>
Date: Fri, 6 Mar 2026 17:29:36 +0100
Subject: [PATCH v2 2/3] Change copyObject() to use typeof_unqual
Currently, when the argument of copyObject() is const-qualified, the
return type is also, because the use of typeof carries over all the
qualifiers. This is incorrect, since the point of copyObject() is to
make a copy to mutate. But apparently no code ran into it.
The new implementation uses typeof_unqual, which drops the qualifiers,
making this work correctly.
typeof_unqual is standardized in C23, but all recent versions of all
the usual compilers support it even in non-C23 mode, at least as
__typeof_unqual__. We add a configure/meson test for typeof_unqual
and __typeof_unqual__ and use it if it's available, else we use the
existing fallback of just returning void *.
We test the underscore variant first so that there is a higher chance
that clang used for bitcode also supports it, since we don't test that
separately.
Unlike the typeof test, the typeof_unqual test also tests with a void
pointer similar to how copyObject() would use it, because that is not
handled by MSVC, so we want the test to fail there.
Reviewed-by: David Geier <[email protected]>
Discussion: https://www.postgresql.org/message-id/flat/92f9750f-c7f6-42d8-9a4a-85a3cbe808f3%40eisentraut.org
---
config/c-compiler.m4 | 65 +++++++++++
configure | 108 ++++++++++++++++++
configure.ac | 2 +
meson.build | 62 ++++++++++
src/include/c.h | 12 ++
src/include/nodes/nodes.h | 4 +-
src/include/pg_config.h.in | 14 +++
.../test_cplusplusext/test_cplusplusext.cpp | 3 +-
8 files changed, 267 insertions(+), 3 deletions(-)
diff --git a/config/c-compiler.m4 b/config/c-compiler.m4
index 5fd768b7332..88333ef301d 100644
--- a/config/c-compiler.m4
+++ b/config/c-compiler.m4
@@ -176,6 +176,40 @@ if test "$pgac_cv_c_typeof" != no; then
fi])# PGAC_C_TYPEOF
+# PGAC_C_TYPEOF_UNQUAL
+# --------------------
+# Check if the C compiler understands typeof_unqual or a variant. Define
+# HAVE_TYPEOF_UNQUAL if so, and define 'typeof_unqual' to the actual key word.
+#
+AC_DEFUN([PGAC_C_TYPEOF_UNQUAL],
+[AC_CACHE_CHECK(for typeof_unqual, pgac_cv_c_typeof_unqual,
+[pgac_cv_c_typeof_unqual=no
+# Test the underscore variant first so that there is a higher chance
+# that clang used for bitcode also supports it, since we don't test
+# that separately.
+#
+# Test with a void pointer, because MSVC doesn't handle that, and we
+# need that for copyObject().
+for pgac_kw in __typeof_unqual__ typeof_unqual; do
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],
+[int x = 0;
+$pgac_kw(x) y;
+const void *a;
+void *b;
+y = x;
+b = ($pgac_kw(*a) *) a;
+return y;])],
+[pgac_cv_c_typeof_unqual=$pgac_kw])
+ test "$pgac_cv_c_typeof_unqual" != no && break
+done])
+if test "$pgac_cv_c_typeof_unqual" != no; then
+ AC_DEFINE(HAVE_TYPEOF_UNQUAL, 1,
+ [Define to 1 if your compiler understands `typeof_unqual' or something similar.])
+ if test "$pgac_cv_c_typeof_unqual" != typeof_unqual; then
+ AC_DEFINE_UNQUOTED(typeof_unqual, $pgac_cv_c_typeof_unqual, [Define to how the compiler spells `typeof_unqual'.])
+ fi
+fi])# PGAC_C_TYPEOF_UNQUAL
+
# PGAC_CXX_TYPEOF
# ----------------
@@ -205,6 +239,37 @@ if test "$pgac_cv_cxx_typeof" != no; then
fi])# PGAC_CXX_TYPEOF
+# PGAC_CXX_TYPEOF_UNQUAL
+# ----------------------
+# Check if the C++ compiler understands typeof_unqual or a variant. Define
+# HAVE_CXX_TYPEOF_UNQUAL if so, and define 'pg_cxx_typeof_unqual' to the actual key word.
+#
+AC_DEFUN([PGAC_CXX_TYPEOF_UNQUAL],
+[AC_CACHE_CHECK(for C++ typeof_unqual, pgac_cv_cxx_typeof_unqual,
+[pgac_cv_cxx_typeof_unqual=no
+AC_LANG_PUSH(C++)
+for pgac_kw in __typeof_unqual__ typeof_unqual; do
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],
+[int x = 0;
+$pgac_kw(x) y;
+const void *a;
+void *b;
+y = x;
+b = ($pgac_kw(*a) *) a;
+return y;])],
+[pgac_cv_cxx_typeof_unqual=$pgac_kw])
+ test "$pgac_cv_cxx_typeof_unqual" != no && break
+done
+AC_LANG_POP([])])
+if test "$pgac_cv_cxx_typeof_unqual" != no; then
+ AC_DEFINE(HAVE_CXX_TYPEOF_UNQUAL, 1,
+ [Define to 1 if your C++ compiler understands `typeof_unqual' or something similar.])
+ if test "$pgac_cv_cxx_typeof_unqual" != typeof_unqual; then
+ AC_DEFINE_UNQUOTED(pg_cxx_typeof_unqual, $pgac_cv_cxx_typeof_unqual, [Define to how the C++ compiler spells `typeof_unqual'.])
+ fi
+fi])# PGAC_CXX_TYPEOF_UNQUAL
+
+
# PGAC_C_TYPES_COMPATIBLE
# -----------------------
diff --git a/configure b/configure
index 4aaaf92ba0a..bef63a8c595 100755
--- a/configure
+++ b/configure
@@ -15101,6 +15101,114 @@ _ACEOF
fi
fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for typeof_unqual" >&5
+$as_echo_n "checking for typeof_unqual... " >&6; }
+if ${pgac_cv_c_typeof_unqual+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ pgac_cv_c_typeof_unqual=no
+# Test the underscore variant first so that there is a higher chance
+# that clang used for bitcode also supports it, since we don't test
+# that separately.
+#
+# Test with a void pointer, because MSVC doesn't handle that, and we
+# need that for copyObject().
+for pgac_kw in __typeof_unqual__ typeof_unqual; do
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+int x = 0;
+$pgac_kw(x) y;
+const void *a;
+void *b;
+y = x;
+b = ($pgac_kw(*a) *) a;
+return y;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ pgac_cv_c_typeof_unqual=$pgac_kw
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ test "$pgac_cv_c_typeof_unqual" != no && break
+done
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $pgac_cv_c_typeof_unqual" >&5
+$as_echo "$pgac_cv_c_typeof_unqual" >&6; }
+if test "$pgac_cv_c_typeof_unqual" != no; then
+
+$as_echo "#define HAVE_TYPEOF_UNQUAL 1" >>confdefs.h
+
+ if test "$pgac_cv_c_typeof_unqual" != typeof_unqual; then
+
+cat >>confdefs.h <<_ACEOF
+#define typeof_unqual $pgac_cv_c_typeof_unqual
+_ACEOF
+
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ typeof_unqual" >&5
+$as_echo_n "checking for C++ typeof_unqual... " >&6; }
+if ${pgac_cv_cxx_typeof_unqual+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ pgac_cv_cxx_typeof_unqual=no
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+
+for pgac_kw in __typeof_unqual__ typeof_unqual; do
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+int x = 0;
+$pgac_kw(x) y;
+const void *a;
+void *b;
+y = x;
+b = ($pgac_kw(*a) *) a;
+return y;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+ pgac_cv_cxx_typeof_unqual=$pgac_kw
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ test "$pgac_cv_cxx_typeof_unqual" != no && break
+done
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $pgac_cv_cxx_typeof_unqual" >&5
+$as_echo "$pgac_cv_cxx_typeof_unqual" >&6; }
+if test "$pgac_cv_cxx_typeof_unqual" != no; then
+
+$as_echo "#define HAVE_CXX_TYPEOF_UNQUAL 1" >>confdefs.h
+
+ if test "$pgac_cv_cxx_typeof_unqual" != typeof_unqual; then
+
+cat >>confdefs.h <<_ACEOF
+#define pg_cxx_typeof_unqual $pgac_cv_cxx_typeof_unqual
+_ACEOF
+
+ fi
+fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for __builtin_types_compatible_p" >&5
$as_echo_n "checking for __builtin_types_compatible_p... " >&6; }
if ${pgac_cv__types_compatible+:} false; then :
diff --git a/configure.ac b/configure.ac
index 9bc457bac87..4d3c69b1c4b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1732,6 +1732,8 @@ PGAC_PRINTF_ARCHETYPE
PGAC_CXX_PRINTF_ARCHETYPE
PGAC_C_TYPEOF
PGAC_CXX_TYPEOF
+PGAC_C_TYPEOF_UNQUAL
+PGAC_CXX_TYPEOF_UNQUAL
PGAC_C_TYPES_COMPATIBLE
PGAC_C_BUILTIN_CONSTANT_P
PGAC_C_BUILTIN_OP_OVERFLOW
diff --git a/meson.build b/meson.build
index 2df54409ca6..70dc64c349a 100644
--- a/meson.build
+++ b/meson.build
@@ -2965,6 +2965,68 @@ int main(void)
endforeach
endif
+# Check if the C compiler understands typeof_unqual or a variant. Define
+# HAVE_TYPEOF_UNQUAL if so, and define 'typeof_unqual' to the actual key word.
+#
+# Test the underscore variant first so that there is a higher chance
+# that clang used for bitcode also supports it, since we don't test
+# that separately.
+#
+# Test with a void pointer, because MSVC doesn't handle that, and we
+# need that for copyObject().
+foreach kw : ['__typeof_unqual__', 'typeof_unqual']
+ if cc.compiles('''
+int main(void)
+{
+ int x = 0;
+ @0@(x) y;
+ const void *a;
+ void *b;
+ y = x;
+ b = (@0@(*a) *) a;
+ return y;
+}
+'''.format(kw),
+ name: kw,
+ args: test_c_args, include_directories: postgres_inc)
+
+ cdata.set('HAVE_TYPEOF_UNQUAL', 1)
+ if kw != 'typeof_unqual'
+ cdata.set('typeof_unqual', kw)
+ endif
+
+ break
+ endif
+endforeach
+
+# Check if the C++ compiler understands typeof_unqual or a variant.
+if have_cxx
+ foreach kw : ['__typeof_unqual__', 'typeof_unqual']
+ if cxx.compiles('''
+int main(void)
+{
+ int x = 0;
+ @0@(x) y;
+ const void *a;
+ void *b;
+ y = x;
+ b = (@0@(*a) *) a;
+ return y;
+}
+'''.format(kw),
+ name: 'C++ ' + kw,
+ args: test_c_args, include_directories: postgres_inc)
+
+ cdata.set('HAVE_CXX_TYPEOF_UNQUAL', 1)
+ if kw != 'typeof_unqual'
+ cdata.set('pg_cxx_typeof_unqual', kw)
+ endif
+
+ break
+ endif
+ endforeach
+endif
+
# MSVC doesn't cope well with defining restrict to __restrict, the
# spelling it understands, because it conflicts with
diff --git a/src/include/c.h b/src/include/c.h
index 5b678283469..2aab74d8b0e 100644
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -452,7 +452,19 @@ extern "C++"
#ifndef HAVE_TYPEOF
#define HAVE_TYPEOF 1
#endif
+/*
+ * and analogously for typeof_unqual
+ */
+#undef typeof_unqual
+#ifdef pg_cxx_typeof_unqual
+#define typeof_unqual(x) pg_cxx_typeof_unqual(x)
+#elif !defined(HAVE_CXX_TYPEOF_UNQUAL)
+#define typeof_unqual(x) std::remove_cv_t<std::remove_reference_t<decltype(x)>>
+#endif
+#ifndef HAVE_TYPEOF_UNQUAL
+#define HAVE_TYPEOF_UNQUAL 1
#endif
+#endif /* __cplusplus */
/*
* CppAsString
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index 59a7df31aba..a2925ae4946 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -226,8 +226,8 @@ extern int16 *readAttrNumberCols(int numCols);
extern void *copyObjectImpl(const void *from);
/* cast result back to argument type, if supported by compiler */
-#ifdef HAVE_TYPEOF
-#define copyObject(obj) ((typeof(obj)) copyObjectImpl(obj))
+#ifdef HAVE_TYPEOF_UNQUAL
+#define copyObject(obj) ((typeof_unqual(*(obj)) *) copyObjectImpl(obj))
#else
#define copyObject(obj) copyObjectImpl(obj)
#endif
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in
index cb0f53fade4..79379a4d125 100644
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -73,6 +73,10 @@
*/
#undef HAVE_CXX_TYPEOF
+/* Define to 1 if your C++ compiler understands `typeof_unqual' or something
+ similar. */
+#undef HAVE_CXX_TYPEOF_UNQUAL
+
/* Define to 1 if you have the declaration of `fdatasync', and to 0 if you
don't. */
#undef HAVE_DECL_FDATASYNC
@@ -458,6 +462,10 @@
/* Define to 1 if your compiler understands `typeof' or something similar. */
#undef HAVE_TYPEOF
+/* Define to 1 if your compiler understands `typeof_unqual' or something
+ similar. */
+#undef HAVE_TYPEOF_UNQUAL
+
/* Define to 1 if you have the <uchar.h> header file. */
#undef HAVE_UCHAR_H
@@ -784,6 +792,9 @@
/* Define to how the C++ compiler spells `typeof'. */
#undef pg_cxx_typeof
+/* Define to how the C++ compiler spells `typeof_unqual'. */
+#undef pg_cxx_typeof_unqual
+
/* Define to keyword to use for C99 restrict support, or to nothing if not
supported */
#undef pg_restrict
@@ -804,3 +815,6 @@
/* Define to how the compiler spells `typeof'. */
#undef typeof
+
+/* Define to how the compiler spells `typeof_unqual'. */
+#undef typeof_unqual
diff --git a/src/test/modules/test_cplusplusext/test_cplusplusext.cpp b/src/test/modules/test_cplusplusext/test_cplusplusext.cpp
index ea04a761184..93cd7dd07f7 100644
--- a/src/test/modules/test_cplusplusext/test_cplusplusext.cpp
+++ b/src/test/modules/test_cplusplusext/test_cplusplusext.cpp
@@ -37,7 +37,8 @@ test_cplusplus_add(PG_FUNCTION_ARGS)
int32 a = PG_GETARG_INT32(0);
int32 b = PG_GETARG_INT32(1);
RangeTblRef *node = makeNode(RangeTblRef);
- RangeTblRef *copy = copyObject(node);
+ const RangeTblRef *nodec = node;
+ RangeTblRef *copy = copyObject(nodec);
List *list = list_make1(node);
foreach_ptr(RangeTblRef, rtr, list)
--
2.53.0
From fe2a62a7b8bad4ce62393ac08af67d81aee962ac Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <[email protected]>
Date: Wed, 4 Feb 2026 08:58:02 +0100
Subject: [PATCH v2 3/3] Add some const qualifiers enabled by typeof_unqual
change on copyObject
The recent commit to change copyObject() to use typeof_unqual allows
cleaning up some APIs to take advantage of this improved qualifier
handling. EventTriggerCollectSimpleCommand() is a good example: It
takes a node tree and makes a copy that it keeps around for its
internal purposes, but it can't communicate via its function signature
that it promises not scribble on the passed node tree. That is now
fixed.
Reviewed-by: David Geier <[email protected]>
Discussion: https://www.postgresql.org/message-id/flat/92f9750f-c7f6-42d8-9a4a-85a3cbe808f3%40eisentraut.org
---
src/backend/catalog/index.c | 2 +-
src/backend/commands/event_trigger.c | 14 +++++++-------
src/backend/commands/indexcmds.c | 4 ++--
src/backend/commands/trigger.c | 4 ++--
src/backend/optimizer/prep/prepjointree.c | 4 ++--
src/backend/partitioning/partprune.c | 12 ++++++------
src/backend/rewrite/rewriteManip.c | 17 ++++++++++-------
src/backend/utils/cache/plancache.c | 2 +-
src/include/commands/defrem.h | 2 +-
src/include/commands/event_trigger.h | 14 +++++++-------
src/include/commands/trigger.h | 4 ++--
src/include/rewrite/rewriteManip.h | 4 ++--
src/include/utils/plancache.h | 2 +-
13 files changed, 44 insertions(+), 41 deletions(-)
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 43de42ce39e..d4ca965df19 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3705,7 +3705,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
ObjectAddressSet(address, RelationRelationId, indexId);
EventTriggerCollectSimpleCommand(address,
InvalidObjectAddress,
- (Node *) stmt);
+ (const Node *) stmt);
}
/*
diff --git a/src/backend/commands/event_trigger.c b/src/backend/commands/event_trigger.c
index 2898967fa67..f9a5aba4360 100644
--- a/src/backend/commands/event_trigger.c
+++ b/src/backend/commands/event_trigger.c
@@ -1714,7 +1714,7 @@ EventTriggerUndoInhibitCommandCollection(void)
void
EventTriggerCollectSimpleCommand(ObjectAddress address,
ObjectAddress secondaryObject,
- Node *parsetree)
+ const Node *parsetree)
{
MemoryContext oldcxt;
CollectedCommand *command;
@@ -1750,7 +1750,7 @@ EventTriggerCollectSimpleCommand(ObjectAddress address,
* add it to the command list.
*/
void
-EventTriggerAlterTableStart(Node *parsetree)
+EventTriggerAlterTableStart(const Node *parsetree)
{
MemoryContext oldcxt;
CollectedCommand *command;
@@ -1802,7 +1802,7 @@ EventTriggerAlterTableRelid(Oid objectId)
* internally, so that's all that this code needs to handle at the moment.
*/
void
-EventTriggerCollectAlterTableSubcmd(Node *subcmd, ObjectAddress address)
+EventTriggerCollectAlterTableSubcmd(const Node *subcmd, ObjectAddress address)
{
MemoryContext oldcxt;
CollectedATSubcmd *newsub;
@@ -1919,7 +1919,7 @@ EventTriggerCollectGrant(InternalGrant *istmt)
* executed
*/
void
-EventTriggerCollectAlterOpFam(AlterOpFamilyStmt *stmt, Oid opfamoid,
+EventTriggerCollectAlterOpFam(const AlterOpFamilyStmt *stmt, Oid opfamoid,
List *operators, List *procedures)
{
MemoryContext oldcxt;
@@ -1952,7 +1952,7 @@ EventTriggerCollectAlterOpFam(AlterOpFamilyStmt *stmt, Oid opfamoid,
* Save data about a CREATE OPERATOR CLASS command being executed
*/
void
-EventTriggerCollectCreateOpClass(CreateOpClassStmt *stmt, Oid opcoid,
+EventTriggerCollectCreateOpClass(const CreateOpClassStmt *stmt, Oid opcoid,
List *operators, List *procedures)
{
MemoryContext oldcxt;
@@ -1986,7 +1986,7 @@ EventTriggerCollectCreateOpClass(CreateOpClassStmt *stmt, Oid opcoid,
* executed
*/
void
-EventTriggerCollectAlterTSConfig(AlterTSConfigurationStmt *stmt, Oid cfgId,
+EventTriggerCollectAlterTSConfig(const AlterTSConfigurationStmt *stmt, Oid cfgId,
Oid *dictIds, int ndicts)
{
MemoryContext oldcxt;
@@ -2024,7 +2024,7 @@ EventTriggerCollectAlterTSConfig(AlterTSConfigurationStmt *stmt, Oid cfgId,
* executed
*/
void
-EventTriggerCollectAlterDefPrivs(AlterDefaultPrivilegesStmt *stmt)
+EventTriggerCollectAlterDefPrivs(const AlterDefaultPrivilegesStmt *stmt)
{
MemoryContext oldcxt;
CollectedCommand *command;
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 635679cc1f2..6c7f8180bc2 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -543,7 +543,7 @@ WaitForOlderSnapshots(TransactionId limitXmin, bool progress)
ObjectAddress
DefineIndex(ParseState *pstate,
Oid tableId,
- IndexStmt *stmt,
+ const IndexStmt *stmt,
Oid indexRelationId,
Oid parentIndexId,
Oid parentConstraintId,
@@ -4047,7 +4047,7 @@ ReindexRelationConcurrently(const ReindexStmt *stmt, Oid relationOid, const Rein
ObjectAddressSet(address, RelationRelationId, newIndexId);
EventTriggerCollectSimpleCommand(address,
InvalidObjectAddress,
- (Node *) stmt);
+ (const Node *) stmt);
}
}
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index 98d402c0a3b..373a08340fa 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -157,7 +157,7 @@ static HeapTuple check_modified_virtual_generated(TupleDesc tupdesc, HeapTuple t
* (but see CloneRowTriggersToPartition).
*/
ObjectAddress
-CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
+CreateTrigger(const CreateTrigStmt *stmt, const char *queryString,
Oid relOid, Oid refRelOid, Oid constraintOid, Oid indexOid,
Oid funcoid, Oid parentTriggerOid, Node *whenClause,
bool isInternal, bool in_partition)
@@ -174,7 +174,7 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
* (always/origin/replica/disabled) can be specified.
*/
ObjectAddress
-CreateTriggerFiringOn(CreateTrigStmt *stmt, const char *queryString,
+CreateTriggerFiringOn(const CreateTrigStmt *stmt, const char *queryString,
Oid relOid, Oid refRelOid, Oid constraintOid,
Oid indexOid, Oid funcoid, Oid parentTriggerOid,
Node *whenClause, bool isInternal, bool in_partition,
diff --git a/src/backend/optimizer/prep/prepjointree.c b/src/backend/optimizer/prep/prepjointree.c
index c90f4b32733..ab621e281e9 100644
--- a/src/backend/optimizer/prep/prepjointree.c
+++ b/src/backend/optimizer/prep/prepjointree.c
@@ -150,7 +150,7 @@ static void replace_vars_in_jointree(Node *jtnode,
pullup_replace_vars_context *context);
static Node *pullup_replace_vars(Node *expr,
pullup_replace_vars_context *context);
-static Node *pullup_replace_vars_callback(Var *var,
+static Node *pullup_replace_vars_callback(const Var *var,
replace_rte_variables_context *context);
static Query *pullup_replace_vars_subquery(Query *query,
pullup_replace_vars_context *context);
@@ -2698,7 +2698,7 @@ pullup_replace_vars(Node *expr, pullup_replace_vars_context *context)
}
static Node *
-pullup_replace_vars_callback(Var *var,
+pullup_replace_vars_callback(const Var *var,
replace_rte_variables_context *context)
{
pullup_replace_vars_context *rcon = (pullup_replace_vars_context *) context->callback_arg;
diff --git a/src/backend/partitioning/partprune.c b/src/backend/partitioning/partprune.c
index 6d979a08fd3..db1dd153ddb 100644
--- a/src/backend/partitioning/partprune.c
+++ b/src/backend/partitioning/partprune.c
@@ -158,7 +158,7 @@ static PartitionPruneStep *gen_prune_step_combine(GeneratePruningStepsContext *c
static List *gen_prune_steps_from_opexps(GeneratePruningStepsContext *context,
List **keyclauses, Bitmapset *nullkeys);
static PartClauseMatchStatus match_clause_to_partition_key(GeneratePruningStepsContext *context,
- Expr *clause, Expr *partkey, int partkeyidx,
+ const Expr *clause, const Expr *partkey, int partkeyidx,
bool *clause_is_not_null,
PartClauseInfo **pc, List **clause_steps);
static List *get_steps_using_prefix(GeneratePruningStepsContext *context,
@@ -196,8 +196,8 @@ static PruneStepResult *perform_pruning_combine_step(PartitionPruneContext *cont
PartitionPruneStepCombine *cstep,
PruneStepResult **step_results);
static PartClauseMatchStatus match_boolean_partition_clause(Oid partopfamily,
- Expr *clause,
- Expr *partkey,
+ const Expr *clause,
+ const Expr *partkey,
Expr **outconst,
bool *notclause);
static void partkey_datum_from_expr(PartitionPruneContext *context,
@@ -1816,7 +1816,7 @@ gen_prune_steps_from_opexps(GeneratePruningStepsContext *context,
*/
static PartClauseMatchStatus
match_clause_to_partition_key(GeneratePruningStepsContext *context,
- Expr *clause, Expr *partkey, int partkeyidx,
+ const Expr *clause, const Expr *partkey, int partkeyidx,
bool *clause_is_not_null, PartClauseInfo **pc,
List **clause_steps)
{
@@ -3697,10 +3697,10 @@ perform_pruning_combine_step(PartitionPruneContext *context,
* 'partkey'.
*/
static PartClauseMatchStatus
-match_boolean_partition_clause(Oid partopfamily, Expr *clause, Expr *partkey,
+match_boolean_partition_clause(Oid partopfamily, const Expr *clause, const Expr *partkey,
Expr **outconst, bool *notclause)
{
- Expr *leftop;
+ const Expr *leftop;
*outconst = NULL;
*notclause = false;
diff --git a/src/backend/rewrite/rewriteManip.c b/src/backend/rewrite/rewriteManip.c
index 6fa174412f2..acd20f61f5a 100644
--- a/src/backend/rewrite/rewriteManip.c
+++ b/src/backend/rewrite/rewriteManip.c
@@ -1768,7 +1768,7 @@ typedef struct
} ReplaceVarsFromTargetList_context;
static Node *
-ReplaceVarsFromTargetList_callback(Var *var,
+ReplaceVarsFromTargetList_callback(const Var *var,
replace_rte_variables_context *context)
{
ReplaceVarsFromTargetList_context *rcon = (ReplaceVarsFromTargetList_context *) context->callback_arg;
@@ -1789,7 +1789,7 @@ ReplaceVarsFromTargetList_callback(Var *var,
}
Node *
-ReplaceVarFromTargetList(Var *var,
+ReplaceVarFromTargetList(const Var *var,
RangeTblEntry *target_rte,
List *targetlist,
int result_relation,
@@ -1875,11 +1875,14 @@ ReplaceVarFromTargetList(Var *var,
break;
case REPLACEVARS_CHANGE_VARNO:
- var = copyObject(var);
- var->varno = nomatch_varno;
- var->varlevelsup = 0;
- /* we leave the syntactic referent alone */
- return (Node *) var;
+ {
+ Var *newvar = copyObject(var);
+
+ newvar->varno = nomatch_varno;
+ newvar->varlevelsup = 0;
+ /* we leave the syntactic referent alone */
+ return (Node *) newvar;
+ }
case REPLACEVARS_SUBSTITUTE_NULL:
{
diff --git a/src/backend/utils/cache/plancache.c b/src/backend/utils/cache/plancache.c
index 812e2265734..d67a914d56d 100644
--- a/src/backend/utils/cache/plancache.c
+++ b/src/backend/utils/cache/plancache.c
@@ -182,7 +182,7 @@ InitPlanCache(void)
* commandTag: command tag for query, or UNKNOWN if empty query
*/
CachedPlanSource *
-CreateCachedPlan(RawStmt *raw_parse_tree,
+CreateCachedPlan(const RawStmt *raw_parse_tree,
const char *query_string,
CommandTag commandTag)
{
diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h
index 8f4a2d9bbc1..d080ad59b71 100644
--- a/src/include/commands/defrem.h
+++ b/src/include/commands/defrem.h
@@ -27,7 +27,7 @@ extern void RemoveObjects(DropStmt *stmt);
/* commands/indexcmds.c */
extern ObjectAddress DefineIndex(ParseState *pstate,
Oid tableId,
- IndexStmt *stmt,
+ const IndexStmt *stmt,
Oid indexRelationId,
Oid parentIndexId,
Oid parentConstraintId,
diff --git a/src/include/commands/event_trigger.h b/src/include/commands/event_trigger.h
index c662782bb1e..27340655061 100644
--- a/src/include/commands/event_trigger.h
+++ b/src/include/commands/event_trigger.h
@@ -75,23 +75,23 @@ extern void EventTriggerUndoInhibitCommandCollection(void);
extern void EventTriggerCollectSimpleCommand(ObjectAddress address,
ObjectAddress secondaryObject,
- Node *parsetree);
+ const Node *parsetree);
-extern void EventTriggerAlterTableStart(Node *parsetree);
+extern void EventTriggerAlterTableStart(const Node *parsetree);
extern void EventTriggerAlterTableRelid(Oid objectId);
-extern void EventTriggerCollectAlterTableSubcmd(Node *subcmd,
+extern void EventTriggerCollectAlterTableSubcmd(const Node *subcmd,
ObjectAddress address);
extern void EventTriggerAlterTableEnd(void);
extern void EventTriggerCollectGrant(InternalGrant *istmt);
-extern void EventTriggerCollectAlterOpFam(AlterOpFamilyStmt *stmt,
+extern void EventTriggerCollectAlterOpFam(const AlterOpFamilyStmt *stmt,
Oid opfamoid, List *operators,
List *procedures);
-extern void EventTriggerCollectCreateOpClass(CreateOpClassStmt *stmt,
+extern void EventTriggerCollectCreateOpClass(const CreateOpClassStmt *stmt,
Oid opcoid, List *operators,
List *procedures);
-extern void EventTriggerCollectAlterTSConfig(AlterTSConfigurationStmt *stmt,
+extern void EventTriggerCollectAlterTSConfig(const AlterTSConfigurationStmt *stmt,
Oid cfgId, Oid *dictIds, int ndicts);
-extern void EventTriggerCollectAlterDefPrivs(AlterDefaultPrivilegesStmt *stmt);
+extern void EventTriggerCollectAlterDefPrivs(const AlterDefaultPrivilegesStmt *stmt);
#endif /* EVENT_TRIGGER_H */
diff --git a/src/include/commands/trigger.h b/src/include/commands/trigger.h
index 556c86bf5e1..27af5284406 100644
--- a/src/include/commands/trigger.h
+++ b/src/include/commands/trigger.h
@@ -153,11 +153,11 @@ extern PGDLLIMPORT int SessionReplicationRole;
#define TRIGGER_FIRES_ON_REPLICA 'R'
#define TRIGGER_DISABLED 'D'
-extern ObjectAddress CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
+extern ObjectAddress CreateTrigger(const CreateTrigStmt *stmt, const char *queryString,
Oid relOid, Oid refRelOid, Oid constraintOid, Oid indexOid,
Oid funcoid, Oid parentTriggerOid, Node *whenClause,
bool isInternal, bool in_partition);
-extern ObjectAddress CreateTriggerFiringOn(CreateTrigStmt *stmt, const char *queryString,
+extern ObjectAddress CreateTriggerFiringOn(const CreateTrigStmt *stmt, const char *queryString,
Oid relOid, Oid refRelOid, Oid constraintOid,
Oid indexOid, Oid funcoid, Oid parentTriggerOid,
Node *whenClause, bool isInternal, bool in_partition,
diff --git a/src/include/rewrite/rewriteManip.h b/src/include/rewrite/rewriteManip.h
index f8216c22fb7..a6d4e888e06 100644
--- a/src/include/rewrite/rewriteManip.h
+++ b/src/include/rewrite/rewriteManip.h
@@ -22,7 +22,7 @@ typedef struct AttrMap AttrMap; /* avoid including attmap.h here */
typedef struct replace_rte_variables_context replace_rte_variables_context;
-typedef Node *(*replace_rte_variables_callback) (Var *var,
+typedef Node *(*replace_rte_variables_callback) (const Var *var,
replace_rte_variables_context *context);
struct replace_rte_variables_context
@@ -104,7 +104,7 @@ extern Node *map_variable_attnos(Node *node,
const AttrMap *attno_map,
Oid to_rowtype, bool *found_whole_row);
-extern Node *ReplaceVarFromTargetList(Var *var,
+extern Node *ReplaceVarFromTargetList(const Var *var,
RangeTblEntry *target_rte,
List *targetlist,
int result_relation,
diff --git a/src/include/utils/plancache.h b/src/include/utils/plancache.h
index 984c51515c6..7a4a85c8038 100644
--- a/src/include/utils/plancache.h
+++ b/src/include/utils/plancache.h
@@ -202,7 +202,7 @@ extern void ResetPlanCache(void);
extern void ReleaseAllPlanCacheRefsInOwner(ResourceOwner owner);
-extern CachedPlanSource *CreateCachedPlan(RawStmt *raw_parse_tree,
+extern CachedPlanSource *CreateCachedPlan(const RawStmt *raw_parse_tree,
const char *query_string,
CommandTag commandTag);
extern CachedPlanSource *CreateCachedPlanForQuery(Query *analyzed_parse_tree,
--
2.53.0
Attachments:
[text/plain] v2-0001-Fixes-for-C-typeof-implementation.patch (1.5K, ../../[email protected]/2-v2-0001-Fixes-for-C-typeof-implementation.patch)
download | inline diff:
From f2f750f7c3ab6b73514ab2fd5f02185abe9ad59f Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <[email protected]>
Date: Fri, 6 Mar 2026 13:31:01 +0100
Subject: [PATCH v2 1/3] Fixes for C++ typeof implementation
This fixes two bugs in commit 1887d822f14.
First, if we are using the fallback C++ implementation of typeof, then
we need to include the C++ header <type_traits> for
std::remove_reference_t. This header is also likely to be used for
other C++ implementations of type tricks, so we'll put it into the
global includes.
Second, for the case that the C compiler supports typeof in a spelling
that is not "typeof" (for example, __typeof__), then we need to #undef
typeof in the C++ section to avoid warnings about duplicate macro
definitions.
---
src/include/c.h | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/src/include/c.h b/src/include/c.h
index f66c752d4a0..5b678283469 100644
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -82,6 +82,14 @@
#endif
#ifdef ENABLE_NLS
#include <libintl.h>
+#endif
+
+#ifdef __cplusplus
+extern "C++"
+{
+/* This header is used in the definition of various C++ things below. */
+#include <type_traits>
+}
#endif
/* Pull in fundamental symbols that we also expose to applications */
@@ -435,6 +443,7 @@
* [1]: https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2927.htm#existing-decltype
*/
#if defined(__cplusplus)
+#undef typeof
#ifdef pg_cxx_typeof
#define typeof(x) pg_cxx_typeof(x)
#elif !defined(HAVE_CXX_TYPEOF)
--
2.53.0
[text/plain] v2-0002-Change-copyObject-to-use-typeof_unqual.patch (13.0K, ../../[email protected]/3-v2-0002-Change-copyObject-to-use-typeof_unqual.patch)
download | inline diff:
From d57d96e3929cd7ef2484e9d3ac95b1c9ba774823 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <[email protected]>
Date: Fri, 6 Mar 2026 17:29:36 +0100
Subject: [PATCH v2 2/3] Change copyObject() to use typeof_unqual
Currently, when the argument of copyObject() is const-qualified, the
return type is also, because the use of typeof carries over all the
qualifiers. This is incorrect, since the point of copyObject() is to
make a copy to mutate. But apparently no code ran into it.
The new implementation uses typeof_unqual, which drops the qualifiers,
making this work correctly.
typeof_unqual is standardized in C23, but all recent versions of all
the usual compilers support it even in non-C23 mode, at least as
__typeof_unqual__. We add a configure/meson test for typeof_unqual
and __typeof_unqual__ and use it if it's available, else we use the
existing fallback of just returning void *.
We test the underscore variant first so that there is a higher chance
that clang used for bitcode also supports it, since we don't test that
separately.
Unlike the typeof test, the typeof_unqual test also tests with a void
pointer similar to how copyObject() would use it, because that is not
handled by MSVC, so we want the test to fail there.
Reviewed-by: David Geier <[email protected]>
Discussion: https://www.postgresql.org/message-id/flat/92f9750f-c7f6-42d8-9a4a-85a3cbe808f3%40eisentraut.org
---
config/c-compiler.m4 | 65 +++++++++++
configure | 108 ++++++++++++++++++
configure.ac | 2 +
meson.build | 62 ++++++++++
src/include/c.h | 12 ++
src/include/nodes/nodes.h | 4 +-
src/include/pg_config.h.in | 14 +++
.../test_cplusplusext/test_cplusplusext.cpp | 3 +-
8 files changed, 267 insertions(+), 3 deletions(-)
diff --git a/config/c-compiler.m4 b/config/c-compiler.m4
index 5fd768b7332..88333ef301d 100644
--- a/config/c-compiler.m4
+++ b/config/c-compiler.m4
@@ -176,6 +176,40 @@ if test "$pgac_cv_c_typeof" != no; then
fi])# PGAC_C_TYPEOF
+# PGAC_C_TYPEOF_UNQUAL
+# --------------------
+# Check if the C compiler understands typeof_unqual or a variant. Define
+# HAVE_TYPEOF_UNQUAL if so, and define 'typeof_unqual' to the actual key word.
+#
+AC_DEFUN([PGAC_C_TYPEOF_UNQUAL],
+[AC_CACHE_CHECK(for typeof_unqual, pgac_cv_c_typeof_unqual,
+[pgac_cv_c_typeof_unqual=no
+# Test the underscore variant first so that there is a higher chance
+# that clang used for bitcode also supports it, since we don't test
+# that separately.
+#
+# Test with a void pointer, because MSVC doesn't handle that, and we
+# need that for copyObject().
+for pgac_kw in __typeof_unqual__ typeof_unqual; do
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],
+[int x = 0;
+$pgac_kw(x) y;
+const void *a;
+void *b;
+y = x;
+b = ($pgac_kw(*a) *) a;
+return y;])],
+[pgac_cv_c_typeof_unqual=$pgac_kw])
+ test "$pgac_cv_c_typeof_unqual" != no && break
+done])
+if test "$pgac_cv_c_typeof_unqual" != no; then
+ AC_DEFINE(HAVE_TYPEOF_UNQUAL, 1,
+ [Define to 1 if your compiler understands `typeof_unqual' or something similar.])
+ if test "$pgac_cv_c_typeof_unqual" != typeof_unqual; then
+ AC_DEFINE_UNQUOTED(typeof_unqual, $pgac_cv_c_typeof_unqual, [Define to how the compiler spells `typeof_unqual'.])
+ fi
+fi])# PGAC_C_TYPEOF_UNQUAL
+
# PGAC_CXX_TYPEOF
# ----------------
@@ -205,6 +239,37 @@ if test "$pgac_cv_cxx_typeof" != no; then
fi])# PGAC_CXX_TYPEOF
+# PGAC_CXX_TYPEOF_UNQUAL
+# ----------------------
+# Check if the C++ compiler understands typeof_unqual or a variant. Define
+# HAVE_CXX_TYPEOF_UNQUAL if so, and define 'pg_cxx_typeof_unqual' to the actual key word.
+#
+AC_DEFUN([PGAC_CXX_TYPEOF_UNQUAL],
+[AC_CACHE_CHECK(for C++ typeof_unqual, pgac_cv_cxx_typeof_unqual,
+[pgac_cv_cxx_typeof_unqual=no
+AC_LANG_PUSH(C++)
+for pgac_kw in __typeof_unqual__ typeof_unqual; do
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],
+[int x = 0;
+$pgac_kw(x) y;
+const void *a;
+void *b;
+y = x;
+b = ($pgac_kw(*a) *) a;
+return y;])],
+[pgac_cv_cxx_typeof_unqual=$pgac_kw])
+ test "$pgac_cv_cxx_typeof_unqual" != no && break
+done
+AC_LANG_POP([])])
+if test "$pgac_cv_cxx_typeof_unqual" != no; then
+ AC_DEFINE(HAVE_CXX_TYPEOF_UNQUAL, 1,
+ [Define to 1 if your C++ compiler understands `typeof_unqual' or something similar.])
+ if test "$pgac_cv_cxx_typeof_unqual" != typeof_unqual; then
+ AC_DEFINE_UNQUOTED(pg_cxx_typeof_unqual, $pgac_cv_cxx_typeof_unqual, [Define to how the C++ compiler spells `typeof_unqual'.])
+ fi
+fi])# PGAC_CXX_TYPEOF_UNQUAL
+
+
# PGAC_C_TYPES_COMPATIBLE
# -----------------------
diff --git a/configure b/configure
index 4aaaf92ba0a..bef63a8c595 100755
--- a/configure
+++ b/configure
@@ -15101,6 +15101,114 @@ _ACEOF
fi
fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for typeof_unqual" >&5
+$as_echo_n "checking for typeof_unqual... " >&6; }
+if ${pgac_cv_c_typeof_unqual+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ pgac_cv_c_typeof_unqual=no
+# Test the underscore variant first so that there is a higher chance
+# that clang used for bitcode also supports it, since we don't test
+# that separately.
+#
+# Test with a void pointer, because MSVC doesn't handle that, and we
+# need that for copyObject().
+for pgac_kw in __typeof_unqual__ typeof_unqual; do
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+int x = 0;
+$pgac_kw(x) y;
+const void *a;
+void *b;
+y = x;
+b = ($pgac_kw(*a) *) a;
+return y;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ pgac_cv_c_typeof_unqual=$pgac_kw
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ test "$pgac_cv_c_typeof_unqual" != no && break
+done
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $pgac_cv_c_typeof_unqual" >&5
+$as_echo "$pgac_cv_c_typeof_unqual" >&6; }
+if test "$pgac_cv_c_typeof_unqual" != no; then
+
+$as_echo "#define HAVE_TYPEOF_UNQUAL 1" >>confdefs.h
+
+ if test "$pgac_cv_c_typeof_unqual" != typeof_unqual; then
+
+cat >>confdefs.h <<_ACEOF
+#define typeof_unqual $pgac_cv_c_typeof_unqual
+_ACEOF
+
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ typeof_unqual" >&5
+$as_echo_n "checking for C++ typeof_unqual... " >&6; }
+if ${pgac_cv_cxx_typeof_unqual+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ pgac_cv_cxx_typeof_unqual=no
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+
+for pgac_kw in __typeof_unqual__ typeof_unqual; do
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+int x = 0;
+$pgac_kw(x) y;
+const void *a;
+void *b;
+y = x;
+b = ($pgac_kw(*a) *) a;
+return y;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+ pgac_cv_cxx_typeof_unqual=$pgac_kw
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ test "$pgac_cv_cxx_typeof_unqual" != no && break
+done
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $pgac_cv_cxx_typeof_unqual" >&5
+$as_echo "$pgac_cv_cxx_typeof_unqual" >&6; }
+if test "$pgac_cv_cxx_typeof_unqual" != no; then
+
+$as_echo "#define HAVE_CXX_TYPEOF_UNQUAL 1" >>confdefs.h
+
+ if test "$pgac_cv_cxx_typeof_unqual" != typeof_unqual; then
+
+cat >>confdefs.h <<_ACEOF
+#define pg_cxx_typeof_unqual $pgac_cv_cxx_typeof_unqual
+_ACEOF
+
+ fi
+fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for __builtin_types_compatible_p" >&5
$as_echo_n "checking for __builtin_types_compatible_p... " >&6; }
if ${pgac_cv__types_compatible+:} false; then :
diff --git a/configure.ac b/configure.ac
index 9bc457bac87..4d3c69b1c4b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1732,6 +1732,8 @@ PGAC_PRINTF_ARCHETYPE
PGAC_CXX_PRINTF_ARCHETYPE
PGAC_C_TYPEOF
PGAC_CXX_TYPEOF
+PGAC_C_TYPEOF_UNQUAL
+PGAC_CXX_TYPEOF_UNQUAL
PGAC_C_TYPES_COMPATIBLE
PGAC_C_BUILTIN_CONSTANT_P
PGAC_C_BUILTIN_OP_OVERFLOW
diff --git a/meson.build b/meson.build
index 2df54409ca6..70dc64c349a 100644
--- a/meson.build
+++ b/meson.build
@@ -2965,6 +2965,68 @@ int main(void)
endforeach
endif
+# Check if the C compiler understands typeof_unqual or a variant. Define
+# HAVE_TYPEOF_UNQUAL if so, and define 'typeof_unqual' to the actual key word.
+#
+# Test the underscore variant first so that there is a higher chance
+# that clang used for bitcode also supports it, since we don't test
+# that separately.
+#
+# Test with a void pointer, because MSVC doesn't handle that, and we
+# need that for copyObject().
+foreach kw : ['__typeof_unqual__', 'typeof_unqual']
+ if cc.compiles('''
+int main(void)
+{
+ int x = 0;
+ @0@(x) y;
+ const void *a;
+ void *b;
+ y = x;
+ b = (@0@(*a) *) a;
+ return y;
+}
+'''.format(kw),
+ name: kw,
+ args: test_c_args, include_directories: postgres_inc)
+
+ cdata.set('HAVE_TYPEOF_UNQUAL', 1)
+ if kw != 'typeof_unqual'
+ cdata.set('typeof_unqual', kw)
+ endif
+
+ break
+ endif
+endforeach
+
+# Check if the C++ compiler understands typeof_unqual or a variant.
+if have_cxx
+ foreach kw : ['__typeof_unqual__', 'typeof_unqual']
+ if cxx.compiles('''
+int main(void)
+{
+ int x = 0;
+ @0@(x) y;
+ const void *a;
+ void *b;
+ y = x;
+ b = (@0@(*a) *) a;
+ return y;
+}
+'''.format(kw),
+ name: 'C++ ' + kw,
+ args: test_c_args, include_directories: postgres_inc)
+
+ cdata.set('HAVE_CXX_TYPEOF_UNQUAL', 1)
+ if kw != 'typeof_unqual'
+ cdata.set('pg_cxx_typeof_unqual', kw)
+ endif
+
+ break
+ endif
+ endforeach
+endif
+
# MSVC doesn't cope well with defining restrict to __restrict, the
# spelling it understands, because it conflicts with
diff --git a/src/include/c.h b/src/include/c.h
index 5b678283469..2aab74d8b0e 100644
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -452,7 +452,19 @@ extern "C++"
#ifndef HAVE_TYPEOF
#define HAVE_TYPEOF 1
#endif
+/*
+ * and analogously for typeof_unqual
+ */
+#undef typeof_unqual
+#ifdef pg_cxx_typeof_unqual
+#define typeof_unqual(x) pg_cxx_typeof_unqual(x)
+#elif !defined(HAVE_CXX_TYPEOF_UNQUAL)
+#define typeof_unqual(x) std::remove_cv_t<std::remove_reference_t<decltype(x)>>
+#endif
+#ifndef HAVE_TYPEOF_UNQUAL
+#define HAVE_TYPEOF_UNQUAL 1
#endif
+#endif /* __cplusplus */
/*
* CppAsString
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index 59a7df31aba..a2925ae4946 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -226,8 +226,8 @@ extern int16 *readAttrNumberCols(int numCols);
extern void *copyObjectImpl(const void *from);
/* cast result back to argument type, if supported by compiler */
-#ifdef HAVE_TYPEOF
-#define copyObject(obj) ((typeof(obj)) copyObjectImpl(obj))
+#ifdef HAVE_TYPEOF_UNQUAL
+#define copyObject(obj) ((typeof_unqual(*(obj)) *) copyObjectImpl(obj))
#else
#define copyObject(obj) copyObjectImpl(obj)
#endif
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in
index cb0f53fade4..79379a4d125 100644
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -73,6 +73,10 @@
*/
#undef HAVE_CXX_TYPEOF
+/* Define to 1 if your C++ compiler understands `typeof_unqual' or something
+ similar. */
+#undef HAVE_CXX_TYPEOF_UNQUAL
+
/* Define to 1 if you have the declaration of `fdatasync', and to 0 if you
don't. */
#undef HAVE_DECL_FDATASYNC
@@ -458,6 +462,10 @@
/* Define to 1 if your compiler understands `typeof' or something similar. */
#undef HAVE_TYPEOF
+/* Define to 1 if your compiler understands `typeof_unqual' or something
+ similar. */
+#undef HAVE_TYPEOF_UNQUAL
+
/* Define to 1 if you have the <uchar.h> header file. */
#undef HAVE_UCHAR_H
@@ -784,6 +792,9 @@
/* Define to how the C++ compiler spells `typeof'. */
#undef pg_cxx_typeof
+/* Define to how the C++ compiler spells `typeof_unqual'. */
+#undef pg_cxx_typeof_unqual
+
/* Define to keyword to use for C99 restrict support, or to nothing if not
supported */
#undef pg_restrict
@@ -804,3 +815,6 @@
/* Define to how the compiler spells `typeof'. */
#undef typeof
+
+/* Define to how the compiler spells `typeof_unqual'. */
+#undef typeof_unqual
diff --git a/src/test/modules/test_cplusplusext/test_cplusplusext.cpp b/src/test/modules/test_cplusplusext/test_cplusplusext.cpp
index ea04a761184..93cd7dd07f7 100644
--- a/src/test/modules/test_cplusplusext/test_cplusplusext.cpp
+++ b/src/test/modules/test_cplusplusext/test_cplusplusext.cpp
@@ -37,7 +37,8 @@ test_cplusplus_add(PG_FUNCTION_ARGS)
int32 a = PG_GETARG_INT32(0);
int32 b = PG_GETARG_INT32(1);
RangeTblRef *node = makeNode(RangeTblRef);
- RangeTblRef *copy = copyObject(node);
+ const RangeTblRef *nodec = node;
+ RangeTblRef *copy = copyObject(nodec);
List *list = list_make1(node);
foreach_ptr(RangeTblRef, rtr, list)
--
2.53.0
[text/plain] v2-0003-Add-some-const-qualifiers-enabled-by-typeof_unqua.patch (16.2K, ../../[email protected]/4-v2-0003-Add-some-const-qualifiers-enabled-by-typeof_unqua.patch)
download | inline diff:
From fe2a62a7b8bad4ce62393ac08af67d81aee962ac Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <[email protected]>
Date: Wed, 4 Feb 2026 08:58:02 +0100
Subject: [PATCH v2 3/3] Add some const qualifiers enabled by typeof_unqual
change on copyObject
The recent commit to change copyObject() to use typeof_unqual allows
cleaning up some APIs to take advantage of this improved qualifier
handling. EventTriggerCollectSimpleCommand() is a good example: It
takes a node tree and makes a copy that it keeps around for its
internal purposes, but it can't communicate via its function signature
that it promises not scribble on the passed node tree. That is now
fixed.
Reviewed-by: David Geier <[email protected]>
Discussion: https://www.postgresql.org/message-id/flat/92f9750f-c7f6-42d8-9a4a-85a3cbe808f3%40eisentraut.org
---
src/backend/catalog/index.c | 2 +-
src/backend/commands/event_trigger.c | 14 +++++++-------
src/backend/commands/indexcmds.c | 4 ++--
src/backend/commands/trigger.c | 4 ++--
src/backend/optimizer/prep/prepjointree.c | 4 ++--
src/backend/partitioning/partprune.c | 12 ++++++------
src/backend/rewrite/rewriteManip.c | 17 ++++++++++-------
src/backend/utils/cache/plancache.c | 2 +-
src/include/commands/defrem.h | 2 +-
src/include/commands/event_trigger.h | 14 +++++++-------
src/include/commands/trigger.h | 4 ++--
src/include/rewrite/rewriteManip.h | 4 ++--
src/include/utils/plancache.h | 2 +-
13 files changed, 44 insertions(+), 41 deletions(-)
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 43de42ce39e..d4ca965df19 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3705,7 +3705,7 @@ reindex_index(const ReindexStmt *stmt, Oid indexId,
ObjectAddressSet(address, RelationRelationId, indexId);
EventTriggerCollectSimpleCommand(address,
InvalidObjectAddress,
- (Node *) stmt);
+ (const Node *) stmt);
}
/*
diff --git a/src/backend/commands/event_trigger.c b/src/backend/commands/event_trigger.c
index 2898967fa67..f9a5aba4360 100644
--- a/src/backend/commands/event_trigger.c
+++ b/src/backend/commands/event_trigger.c
@@ -1714,7 +1714,7 @@ EventTriggerUndoInhibitCommandCollection(void)
void
EventTriggerCollectSimpleCommand(ObjectAddress address,
ObjectAddress secondaryObject,
- Node *parsetree)
+ const Node *parsetree)
{
MemoryContext oldcxt;
CollectedCommand *command;
@@ -1750,7 +1750,7 @@ EventTriggerCollectSimpleCommand(ObjectAddress address,
* add it to the command list.
*/
void
-EventTriggerAlterTableStart(Node *parsetree)
+EventTriggerAlterTableStart(const Node *parsetree)
{
MemoryContext oldcxt;
CollectedCommand *command;
@@ -1802,7 +1802,7 @@ EventTriggerAlterTableRelid(Oid objectId)
* internally, so that's all that this code needs to handle at the moment.
*/
void
-EventTriggerCollectAlterTableSubcmd(Node *subcmd, ObjectAddress address)
+EventTriggerCollectAlterTableSubcmd(const Node *subcmd, ObjectAddress address)
{
MemoryContext oldcxt;
CollectedATSubcmd *newsub;
@@ -1919,7 +1919,7 @@ EventTriggerCollectGrant(InternalGrant *istmt)
* executed
*/
void
-EventTriggerCollectAlterOpFam(AlterOpFamilyStmt *stmt, Oid opfamoid,
+EventTriggerCollectAlterOpFam(const AlterOpFamilyStmt *stmt, Oid opfamoid,
List *operators, List *procedures)
{
MemoryContext oldcxt;
@@ -1952,7 +1952,7 @@ EventTriggerCollectAlterOpFam(AlterOpFamilyStmt *stmt, Oid opfamoid,
* Save data about a CREATE OPERATOR CLASS command being executed
*/
void
-EventTriggerCollectCreateOpClass(CreateOpClassStmt *stmt, Oid opcoid,
+EventTriggerCollectCreateOpClass(const CreateOpClassStmt *stmt, Oid opcoid,
List *operators, List *procedures)
{
MemoryContext oldcxt;
@@ -1986,7 +1986,7 @@ EventTriggerCollectCreateOpClass(CreateOpClassStmt *stmt, Oid opcoid,
* executed
*/
void
-EventTriggerCollectAlterTSConfig(AlterTSConfigurationStmt *stmt, Oid cfgId,
+EventTriggerCollectAlterTSConfig(const AlterTSConfigurationStmt *stmt, Oid cfgId,
Oid *dictIds, int ndicts)
{
MemoryContext oldcxt;
@@ -2024,7 +2024,7 @@ EventTriggerCollectAlterTSConfig(AlterTSConfigurationStmt *stmt, Oid cfgId,
* executed
*/
void
-EventTriggerCollectAlterDefPrivs(AlterDefaultPrivilegesStmt *stmt)
+EventTriggerCollectAlterDefPrivs(const AlterDefaultPrivilegesStmt *stmt)
{
MemoryContext oldcxt;
CollectedCommand *command;
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 635679cc1f2..6c7f8180bc2 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -543,7 +543,7 @@ WaitForOlderSnapshots(TransactionId limitXmin, bool progress)
ObjectAddress
DefineIndex(ParseState *pstate,
Oid tableId,
- IndexStmt *stmt,
+ const IndexStmt *stmt,
Oid indexRelationId,
Oid parentIndexId,
Oid parentConstraintId,
@@ -4047,7 +4047,7 @@ ReindexRelationConcurrently(const ReindexStmt *stmt, Oid relationOid, const Rein
ObjectAddressSet(address, RelationRelationId, newIndexId);
EventTriggerCollectSimpleCommand(address,
InvalidObjectAddress,
- (Node *) stmt);
+ (const Node *) stmt);
}
}
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index 98d402c0a3b..373a08340fa 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -157,7 +157,7 @@ static HeapTuple check_modified_virtual_generated(TupleDesc tupdesc, HeapTuple t
* (but see CloneRowTriggersToPartition).
*/
ObjectAddress
-CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
+CreateTrigger(const CreateTrigStmt *stmt, const char *queryString,
Oid relOid, Oid refRelOid, Oid constraintOid, Oid indexOid,
Oid funcoid, Oid parentTriggerOid, Node *whenClause,
bool isInternal, bool in_partition)
@@ -174,7 +174,7 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
* (always/origin/replica/disabled) can be specified.
*/
ObjectAddress
-CreateTriggerFiringOn(CreateTrigStmt *stmt, const char *queryString,
+CreateTriggerFiringOn(const CreateTrigStmt *stmt, const char *queryString,
Oid relOid, Oid refRelOid, Oid constraintOid,
Oid indexOid, Oid funcoid, Oid parentTriggerOid,
Node *whenClause, bool isInternal, bool in_partition,
diff --git a/src/backend/optimizer/prep/prepjointree.c b/src/backend/optimizer/prep/prepjointree.c
index c90f4b32733..ab621e281e9 100644
--- a/src/backend/optimizer/prep/prepjointree.c
+++ b/src/backend/optimizer/prep/prepjointree.c
@@ -150,7 +150,7 @@ static void replace_vars_in_jointree(Node *jtnode,
pullup_replace_vars_context *context);
static Node *pullup_replace_vars(Node *expr,
pullup_replace_vars_context *context);
-static Node *pullup_replace_vars_callback(Var *var,
+static Node *pullup_replace_vars_callback(const Var *var,
replace_rte_variables_context *context);
static Query *pullup_replace_vars_subquery(Query *query,
pullup_replace_vars_context *context);
@@ -2698,7 +2698,7 @@ pullup_replace_vars(Node *expr, pullup_replace_vars_context *context)
}
static Node *
-pullup_replace_vars_callback(Var *var,
+pullup_replace_vars_callback(const Var *var,
replace_rte_variables_context *context)
{
pullup_replace_vars_context *rcon = (pullup_replace_vars_context *) context->callback_arg;
diff --git a/src/backend/partitioning/partprune.c b/src/backend/partitioning/partprune.c
index 6d979a08fd3..db1dd153ddb 100644
--- a/src/backend/partitioning/partprune.c
+++ b/src/backend/partitioning/partprune.c
@@ -158,7 +158,7 @@ static PartitionPruneStep *gen_prune_step_combine(GeneratePruningStepsContext *c
static List *gen_prune_steps_from_opexps(GeneratePruningStepsContext *context,
List **keyclauses, Bitmapset *nullkeys);
static PartClauseMatchStatus match_clause_to_partition_key(GeneratePruningStepsContext *context,
- Expr *clause, Expr *partkey, int partkeyidx,
+ const Expr *clause, const Expr *partkey, int partkeyidx,
bool *clause_is_not_null,
PartClauseInfo **pc, List **clause_steps);
static List *get_steps_using_prefix(GeneratePruningStepsContext *context,
@@ -196,8 +196,8 @@ static PruneStepResult *perform_pruning_combine_step(PartitionPruneContext *cont
PartitionPruneStepCombine *cstep,
PruneStepResult **step_results);
static PartClauseMatchStatus match_boolean_partition_clause(Oid partopfamily,
- Expr *clause,
- Expr *partkey,
+ const Expr *clause,
+ const Expr *partkey,
Expr **outconst,
bool *notclause);
static void partkey_datum_from_expr(PartitionPruneContext *context,
@@ -1816,7 +1816,7 @@ gen_prune_steps_from_opexps(GeneratePruningStepsContext *context,
*/
static PartClauseMatchStatus
match_clause_to_partition_key(GeneratePruningStepsContext *context,
- Expr *clause, Expr *partkey, int partkeyidx,
+ const Expr *clause, const Expr *partkey, int partkeyidx,
bool *clause_is_not_null, PartClauseInfo **pc,
List **clause_steps)
{
@@ -3697,10 +3697,10 @@ perform_pruning_combine_step(PartitionPruneContext *context,
* 'partkey'.
*/
static PartClauseMatchStatus
-match_boolean_partition_clause(Oid partopfamily, Expr *clause, Expr *partkey,
+match_boolean_partition_clause(Oid partopfamily, const Expr *clause, const Expr *partkey,
Expr **outconst, bool *notclause)
{
- Expr *leftop;
+ const Expr *leftop;
*outconst = NULL;
*notclause = false;
diff --git a/src/backend/rewrite/rewriteManip.c b/src/backend/rewrite/rewriteManip.c
index 6fa174412f2..acd20f61f5a 100644
--- a/src/backend/rewrite/rewriteManip.c
+++ b/src/backend/rewrite/rewriteManip.c
@@ -1768,7 +1768,7 @@ typedef struct
} ReplaceVarsFromTargetList_context;
static Node *
-ReplaceVarsFromTargetList_callback(Var *var,
+ReplaceVarsFromTargetList_callback(const Var *var,
replace_rte_variables_context *context)
{
ReplaceVarsFromTargetList_context *rcon = (ReplaceVarsFromTargetList_context *) context->callback_arg;
@@ -1789,7 +1789,7 @@ ReplaceVarsFromTargetList_callback(Var *var,
}
Node *
-ReplaceVarFromTargetList(Var *var,
+ReplaceVarFromTargetList(const Var *var,
RangeTblEntry *target_rte,
List *targetlist,
int result_relation,
@@ -1875,11 +1875,14 @@ ReplaceVarFromTargetList(Var *var,
break;
case REPLACEVARS_CHANGE_VARNO:
- var = copyObject(var);
- var->varno = nomatch_varno;
- var->varlevelsup = 0;
- /* we leave the syntactic referent alone */
- return (Node *) var;
+ {
+ Var *newvar = copyObject(var);
+
+ newvar->varno = nomatch_varno;
+ newvar->varlevelsup = 0;
+ /* we leave the syntactic referent alone */
+ return (Node *) newvar;
+ }
case REPLACEVARS_SUBSTITUTE_NULL:
{
diff --git a/src/backend/utils/cache/plancache.c b/src/backend/utils/cache/plancache.c
index 812e2265734..d67a914d56d 100644
--- a/src/backend/utils/cache/plancache.c
+++ b/src/backend/utils/cache/plancache.c
@@ -182,7 +182,7 @@ InitPlanCache(void)
* commandTag: command tag for query, or UNKNOWN if empty query
*/
CachedPlanSource *
-CreateCachedPlan(RawStmt *raw_parse_tree,
+CreateCachedPlan(const RawStmt *raw_parse_tree,
const char *query_string,
CommandTag commandTag)
{
diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h
index 8f4a2d9bbc1..d080ad59b71 100644
--- a/src/include/commands/defrem.h
+++ b/src/include/commands/defrem.h
@@ -27,7 +27,7 @@ extern void RemoveObjects(DropStmt *stmt);
/* commands/indexcmds.c */
extern ObjectAddress DefineIndex(ParseState *pstate,
Oid tableId,
- IndexStmt *stmt,
+ const IndexStmt *stmt,
Oid indexRelationId,
Oid parentIndexId,
Oid parentConstraintId,
diff --git a/src/include/commands/event_trigger.h b/src/include/commands/event_trigger.h
index c662782bb1e..27340655061 100644
--- a/src/include/commands/event_trigger.h
+++ b/src/include/commands/event_trigger.h
@@ -75,23 +75,23 @@ extern void EventTriggerUndoInhibitCommandCollection(void);
extern void EventTriggerCollectSimpleCommand(ObjectAddress address,
ObjectAddress secondaryObject,
- Node *parsetree);
+ const Node *parsetree);
-extern void EventTriggerAlterTableStart(Node *parsetree);
+extern void EventTriggerAlterTableStart(const Node *parsetree);
extern void EventTriggerAlterTableRelid(Oid objectId);
-extern void EventTriggerCollectAlterTableSubcmd(Node *subcmd,
+extern void EventTriggerCollectAlterTableSubcmd(const Node *subcmd,
ObjectAddress address);
extern void EventTriggerAlterTableEnd(void);
extern void EventTriggerCollectGrant(InternalGrant *istmt);
-extern void EventTriggerCollectAlterOpFam(AlterOpFamilyStmt *stmt,
+extern void EventTriggerCollectAlterOpFam(const AlterOpFamilyStmt *stmt,
Oid opfamoid, List *operators,
List *procedures);
-extern void EventTriggerCollectCreateOpClass(CreateOpClassStmt *stmt,
+extern void EventTriggerCollectCreateOpClass(const CreateOpClassStmt *stmt,
Oid opcoid, List *operators,
List *procedures);
-extern void EventTriggerCollectAlterTSConfig(AlterTSConfigurationStmt *stmt,
+extern void EventTriggerCollectAlterTSConfig(const AlterTSConfigurationStmt *stmt,
Oid cfgId, Oid *dictIds, int ndicts);
-extern void EventTriggerCollectAlterDefPrivs(AlterDefaultPrivilegesStmt *stmt);
+extern void EventTriggerCollectAlterDefPrivs(const AlterDefaultPrivilegesStmt *stmt);
#endif /* EVENT_TRIGGER_H */
diff --git a/src/include/commands/trigger.h b/src/include/commands/trigger.h
index 556c86bf5e1..27af5284406 100644
--- a/src/include/commands/trigger.h
+++ b/src/include/commands/trigger.h
@@ -153,11 +153,11 @@ extern PGDLLIMPORT int SessionReplicationRole;
#define TRIGGER_FIRES_ON_REPLICA 'R'
#define TRIGGER_DISABLED 'D'
-extern ObjectAddress CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
+extern ObjectAddress CreateTrigger(const CreateTrigStmt *stmt, const char *queryString,
Oid relOid, Oid refRelOid, Oid constraintOid, Oid indexOid,
Oid funcoid, Oid parentTriggerOid, Node *whenClause,
bool isInternal, bool in_partition);
-extern ObjectAddress CreateTriggerFiringOn(CreateTrigStmt *stmt, const char *queryString,
+extern ObjectAddress CreateTriggerFiringOn(const CreateTrigStmt *stmt, const char *queryString,
Oid relOid, Oid refRelOid, Oid constraintOid,
Oid indexOid, Oid funcoid, Oid parentTriggerOid,
Node *whenClause, bool isInternal, bool in_partition,
diff --git a/src/include/rewrite/rewriteManip.h b/src/include/rewrite/rewriteManip.h
index f8216c22fb7..a6d4e888e06 100644
--- a/src/include/rewrite/rewriteManip.h
+++ b/src/include/rewrite/rewriteManip.h
@@ -22,7 +22,7 @@ typedef struct AttrMap AttrMap; /* avoid including attmap.h here */
typedef struct replace_rte_variables_context replace_rte_variables_context;
-typedef Node *(*replace_rte_variables_callback) (Var *var,
+typedef Node *(*replace_rte_variables_callback) (const Var *var,
replace_rte_variables_context *context);
struct replace_rte_variables_context
@@ -104,7 +104,7 @@ extern Node *map_variable_attnos(Node *node,
const AttrMap *attno_map,
Oid to_rowtype, bool *found_whole_row);
-extern Node *ReplaceVarFromTargetList(Var *var,
+extern Node *ReplaceVarFromTargetList(const Var *var,
RangeTblEntry *target_rte,
List *targetlist,
int result_relation,
diff --git a/src/include/utils/plancache.h b/src/include/utils/plancache.h
index 984c51515c6..7a4a85c8038 100644
--- a/src/include/utils/plancache.h
+++ b/src/include/utils/plancache.h
@@ -202,7 +202,7 @@ extern void ResetPlanCache(void);
extern void ReleaseAllPlanCacheRefsInOwner(ResourceOwner owner);
-extern CachedPlanSource *CreateCachedPlan(RawStmt *raw_parse_tree,
+extern CachedPlanSource *CreateCachedPlan(const RawStmt *raw_parse_tree,
const char *query_string,
CommandTag commandTag);
extern CachedPlanSource *CreateCachedPlanForQuery(Query *analyzed_parse_tree,
--
2.53.0
^ permalink raw reply [nested|flat] 26+ messages in thread
* Re: Change copyObject() to use typeof_unqual
2026-03-06 19:17 Re: Change copyObject() to use typeof_unqual Peter Eisentraut <[email protected]>
@ 2026-03-07 00:17 ` Jelte Fennema-Nio <[email protected]>
2026-03-13 10:43 ` Re: Change copyObject() to use typeof_unqual Peter Eisentraut <[email protected]>
1 sibling, 1 reply; 26+ messages in thread
From: Jelte Fennema-Nio @ 2026-03-07 00:17 UTC (permalink / raw)
To: Peter Eisentraut <[email protected]>; +Cc: pgsql-hackers
On Fri, 6 Mar 2026 at 20:17, Peter Eisentraut <[email protected]> wrote:
> This revealed an insufficiency in that commit, which I fix in the first
> patch.
Thanks!
> I have addressed the above problem by swapping the order of the probes
> (putting the underscore variant first), as discussed.
Annoying that this is needed, but I agree that it's the least bad
option in this case.
^ permalink raw reply [nested|flat] 26+ messages in thread
* Re: Change copyObject() to use typeof_unqual
2026-03-06 19:17 Re: Change copyObject() to use typeof_unqual Peter Eisentraut <[email protected]>
2026-03-07 00:17 ` Re: Change copyObject() to use typeof_unqual Jelte Fennema-Nio <[email protected]>
@ 2026-03-13 10:43 ` Peter Eisentraut <[email protected]>
2026-03-13 16:00 ` Re: Change copyObject() to use typeof_unqual Peter Eisentraut <[email protected]>
2026-03-15 21:54 ` Re: Change copyObject() to use typeof_unqual Jelte Fennema-Nio <[email protected]>
0 siblings, 2 replies; 26+ messages in thread
From: Peter Eisentraut @ 2026-03-13 10:43 UTC (permalink / raw)
To: Jelte Fennema-Nio <[email protected]>; +Cc: pgsql-hackers
On 07.03.26 01:17, Jelte Fennema-Nio wrote:
> On Fri, 6 Mar 2026 at 20:17, Peter Eisentraut <[email protected]> wrote:
>> This revealed an insufficiency in that commit, which I fix in the first
>> patch.
>
> Thanks!
There is a failure related to this on buildfarm member sevengill:
../pgsql/src/test/modules/test_cplusplusext/test_cplusplusext.cpp:41:22:
error: no template named 'remove_reference_t' in namespace 'std'; did
you mean 'remove_reference'?
I don't know how that makes sense. Maybe this is a problem in the local
installation of the compiler or standard library.
(This is also a bit suspicious because AFAICT, clang 15 defaults to
C++14, but on that animal it thinks it needs to add -std=gnu++11.)
>> I have addressed the above problem by swapping the order of the probes
>> (putting the underscore variant first), as discussed.
>
> Annoying that this is needed, but I agree that it's the least bad
> option in this case.
I committed this and it still fails, but the failure is now narrower.
There is a failure on buildfarm member taipan because it uses an unusual
combination of gcc and clang (the gcc is much newer than clang). The
only sensible workaround I could think of is a hardcoded override based
on the clang version, as in the attached patch. And alternative is that
we decide that we don't want to support this combination, meaning that
we would effectively require that clang is approximately as-old-or-newer
than gcc.
From 5295cbb0a4573ea886f21d4f5e89ce7beaf60f58 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <[email protected]>
Date: Fri, 13 Mar 2026 11:20:31 +0100
Subject: [PATCH] Hardcode override of typeof_unqual for clang-for-bitcode
The fundamental problem is that when we call clang to generate
bitcode, we might be using configure results from a different
compiler, which might not be fully compatible with the clang we are
using. In practice, clang supports most things other compilers
support, so this has apparently not been a problem in practice.
But commits 4cfce4e62c8, 0af05b5dbb4, and 59292f7aac7 have been
struggling to make typeof_unqual work in this situation. Clang added
support in version 19, GCC in version 14, so if you are using, say,
GCC 14 and Clang 16, the compilation with the latter will fail.
Again, in practice, this might be unlikely, because GCC 14 and Clang
19 were released within a few months of each other, and so Linux
distributions are likely to have suitable combinations. But buildfarm
member "taipan" does not (gcc 15, clang 16), so I'll try to fix it.
The fully correct solution would be to run a separate set of configure
tests for that clang-for-bitcode, but that would be very difficult to
implement, and probably of limited use in practice. So the workaround
here is that we hardcodedly override the configure result under clang
based on the version number. As long as we only have a few of these
cases, this should be manageable.
Discussion: https://www.postgresql.org/message-id/flat/92f9750f-c7f6-42d8-9a4a-85a3cbe808f3%40eisentraut.org
---
src/include/c.h | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/src/include/c.h b/src/include/c.h
index 2aab74d8b0e..2e789b00594 100644
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -432,6 +432,21 @@ extern "C++"
#define unlikely(x) ((x) != 0)
#endif
+/*
+ * When we call clang to generate bitcode, we might be using configure results
+ * from a different compiler, which might not be fully compatible with the
+ * clang we are using. The fully correct solution would be to run a separate
+ * set of configure tests for that clang-for-bitcode, but that could be very
+ * difficult to implement, and in practice clang supports most things other
+ * compilers support. So this section just contains some hardcoded ugliness
+ * to override some configure results where it is necessary.
+ */
+#if defined(__clang__)
+#if __clang_major__ < 19
+#undef HAVE_TYPEOF_UNQUAL
+#endif
+#endif /* __clang__ */
+
/*
* Provide typeof in C++ for C++ compilers that don't support typeof natively.
* It might be spelled __typeof__ instead of typeof, in which case
--
2.53.0
Attachments:
[text/plain] 0001-Hardcode-override-of-typeof_unqual-for-clang-for-bit.patch (2.6K, ../../[email protected]/2-0001-Hardcode-override-of-typeof_unqual-for-clang-for-bit.patch)
download | inline diff:
From 5295cbb0a4573ea886f21d4f5e89ce7beaf60f58 Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <[email protected]>
Date: Fri, 13 Mar 2026 11:20:31 +0100
Subject: [PATCH] Hardcode override of typeof_unqual for clang-for-bitcode
The fundamental problem is that when we call clang to generate
bitcode, we might be using configure results from a different
compiler, which might not be fully compatible with the clang we are
using. In practice, clang supports most things other compilers
support, so this has apparently not been a problem in practice.
But commits 4cfce4e62c8, 0af05b5dbb4, and 59292f7aac7 have been
struggling to make typeof_unqual work in this situation. Clang added
support in version 19, GCC in version 14, so if you are using, say,
GCC 14 and Clang 16, the compilation with the latter will fail.
Again, in practice, this might be unlikely, because GCC 14 and Clang
19 were released within a few months of each other, and so Linux
distributions are likely to have suitable combinations. But buildfarm
member "taipan" does not (gcc 15, clang 16), so I'll try to fix it.
The fully correct solution would be to run a separate set of configure
tests for that clang-for-bitcode, but that would be very difficult to
implement, and probably of limited use in practice. So the workaround
here is that we hardcodedly override the configure result under clang
based on the version number. As long as we only have a few of these
cases, this should be manageable.
Discussion: https://www.postgresql.org/message-id/flat/92f9750f-c7f6-42d8-9a4a-85a3cbe808f3%40eisentraut.org
---
src/include/c.h | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/src/include/c.h b/src/include/c.h
index 2aab74d8b0e..2e789b00594 100644
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -432,6 +432,21 @@ extern "C++"
#define unlikely(x) ((x) != 0)
#endif
+/*
+ * When we call clang to generate bitcode, we might be using configure results
+ * from a different compiler, which might not be fully compatible with the
+ * clang we are using. The fully correct solution would be to run a separate
+ * set of configure tests for that clang-for-bitcode, but that could be very
+ * difficult to implement, and in practice clang supports most things other
+ * compilers support. So this section just contains some hardcoded ugliness
+ * to override some configure results where it is necessary.
+ */
+#if defined(__clang__)
+#if __clang_major__ < 19
+#undef HAVE_TYPEOF_UNQUAL
+#endif
+#endif /* __clang__ */
+
/*
* Provide typeof in C++ for C++ compilers that don't support typeof natively.
* It might be spelled __typeof__ instead of typeof, in which case
--
2.53.0
^ permalink raw reply [nested|flat] 26+ messages in thread
* Re: Change copyObject() to use typeof_unqual
2026-03-06 19:17 Re: Change copyObject() to use typeof_unqual Peter Eisentraut <[email protected]>
2026-03-07 00:17 ` Re: Change copyObject() to use typeof_unqual Jelte Fennema-Nio <[email protected]>
2026-03-13 10:43 ` Re: Change copyObject() to use typeof_unqual Peter Eisentraut <[email protected]>
@ 2026-03-13 16:00 ` Peter Eisentraut <[email protected]>
2026-03-13 16:15 ` Re: Change copyObject() to use typeof_unqual Jelte Fennema-Nio <[email protected]>
1 sibling, 1 reply; 26+ messages in thread
From: Peter Eisentraut @ 2026-03-13 16:00 UTC (permalink / raw)
To: Daniel Gustafsson <[email protected]>; +Cc: Jelte Fennema-Nio <[email protected]>; pgsql-hackers
On 13.03.26 14:03, Daniel Gustafsson wrote:
>> On 13 Mar 2026, at 11:43, Peter Eisentraut <[email protected]> wrote:
>
>> I committed this and it still fails, but the failure is now narrower. There is a failure on buildfarm member taipan because it uses an unusual combination of gcc and clang (the gcc is much newer than clang). The only sensible workaround I could think of is a hardcoded override based on the clang version, as in the attached patch. And alternative is that we decide that we don't want to support this combination, meaning that we would effectively require that clang is approximately as-old-or-newer than gcc.
>
> I ran into this as well on clang 15 via XCode with no gcc involved:
>
> ../src/test/modules/test_cplusplusext/test_cplusplusext.cpp:41:22: error: no template named 'remove_reference_t' in namespace 'std'; did you mean 'remove_reference'?
> RangeTblRef *copy = copyObject(nodec);
> ^~~~~~~~~~~~~~~~~
Jelte,
I read here
https://en.cppreference.com/w/cpp/types/remove_reference.html
that remove_reference_t is actually in C++14, which might explain this
failure, if the compiler is in C++11 mode.
I don't understand the difference between remove_reference and
remove_reference_t.
^ permalink raw reply [nested|flat] 26+ messages in thread
* Re: Change copyObject() to use typeof_unqual
2026-03-06 19:17 Re: Change copyObject() to use typeof_unqual Peter Eisentraut <[email protected]>
2026-03-07 00:17 ` Re: Change copyObject() to use typeof_unqual Jelte Fennema-Nio <[email protected]>
2026-03-13 10:43 ` Re: Change copyObject() to use typeof_unqual Peter Eisentraut <[email protected]>
2026-03-13 16:00 ` Re: Change copyObject() to use typeof_unqual Peter Eisentraut <[email protected]>
@ 2026-03-13 16:15 ` Jelte Fennema-Nio <[email protected]>
2026-03-13 16:18 ` Re: Change copyObject() to use typeof_unqual Jelte Fennema-Nio <[email protected]>
0 siblings, 1 reply; 26+ messages in thread
From: Jelte Fennema-Nio @ 2026-03-13 16:15 UTC (permalink / raw)
To: Peter Eisentraut <[email protected]>; +Cc: Daniel Gustafsson <[email protected]>; pgsql-hackers
On Fri, 13 Mar 2026 at 17:00, Peter Eisentraut <[email protected]> wrote:
> that remove_reference_t is actually in C++14, which might explain this
> failure, if the compiler is in C++11 mode.
Yeah that's almost certainly it... Sorry about that.
> I don't understand the difference between remove_reference and
> remove_reference_t.
They are equivalent only the _t version as a bit less verbose.
Attached should fix it.
Attachments:
[text/x-patch] fix.patch (422B, ../../CAGECzQR-t-Zq6p3KAkohfWcOMGoaqNUqAGj9WC3PxA_zynqEVw@mail.gmail.com/2-fix.patch)
download | inline diff:
diff --git a/src/include/c.h b/src/include/c.h
index 2aab74d8b0e..b4a37661795 100644
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -447,7 +447,7 @@ extern "C++"
#ifdef pg_cxx_typeof
#define typeof(x) pg_cxx_typeof(x)
#elif !defined(HAVE_CXX_TYPEOF)
-#define typeof(x) std::remove_reference_t<decltype(x)>
+#define typeof(x) std::remove_reference<decltype(x)>::value
#endif
#ifndef HAVE_TYPEOF
#define HAVE_TYPEOF 1
^ permalink raw reply [nested|flat] 26+ messages in thread
* Re: Change copyObject() to use typeof_unqual
2026-03-06 19:17 Re: Change copyObject() to use typeof_unqual Peter Eisentraut <[email protected]>
2026-03-07 00:17 ` Re: Change copyObject() to use typeof_unqual Jelte Fennema-Nio <[email protected]>
2026-03-13 10:43 ` Re: Change copyObject() to use typeof_unqual Peter Eisentraut <[email protected]>
2026-03-13 16:00 ` Re: Change copyObject() to use typeof_unqual Peter Eisentraut <[email protected]>
2026-03-13 16:15 ` Re: Change copyObject() to use typeof_unqual Jelte Fennema-Nio <[email protected]>
@ 2026-03-13 16:18 ` Jelte Fennema-Nio <[email protected]>
2026-03-14 13:41 ` Re: Change copyObject() to use typeof_unqual Jelte Fennema-Nio <[email protected]>
0 siblings, 1 reply; 26+ messages in thread
From: Jelte Fennema-Nio @ 2026-03-13 16:18 UTC (permalink / raw)
To: Peter Eisentraut <[email protected]>; +Cc: Daniel Gustafsson <[email protected]>; pgsql-hackers
On Fri, 13 Mar 2026 at 17:15, Jelte Fennema-Nio <[email protected]> wrote:
> Attached should fix it.
Okay corrected in this v2, which fixes all of the places I could find.
Attachments:
[text/x-patch] fix-v2.patch (812B, ../../CAGECzQSzXop4L4=y297r8cCjfwLv8mwUi1pxN3ufevbeXSVLNA@mail.gmail.com/2-fix-v2.patch)
download | inline diff:
diff --git a/src/include/c.h b/src/include/c.h
index 2aab74d8b0e..323dd7df329 100644
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -447,7 +447,7 @@ extern "C++"
#ifdef pg_cxx_typeof
#define typeof(x) pg_cxx_typeof(x)
#elif !defined(HAVE_CXX_TYPEOF)
-#define typeof(x) std::remove_reference_t<decltype(x)>
+#define typeof(x) std::remove_reference<decltype(x)>::value
#endif
#ifndef HAVE_TYPEOF
#define HAVE_TYPEOF 1
@@ -459,7 +459,7 @@ extern "C++"
#ifdef pg_cxx_typeof_unqual
#define typeof_unqual(x) pg_cxx_typeof_unqual(x)
#elif !defined(HAVE_CXX_TYPEOF_UNQUAL)
-#define typeof_unqual(x) std::remove_cv_t<std::remove_reference_t<decltype(x)>>
+#define typeof_unqual(x) std::remove_cv<std::remove_reference<decltype(x)>::value>::value
#endif
#ifndef HAVE_TYPEOF_UNQUAL
#define HAVE_TYPEOF_UNQUAL 1
^ permalink raw reply [nested|flat] 26+ messages in thread
* Re: Change copyObject() to use typeof_unqual
2026-03-06 19:17 Re: Change copyObject() to use typeof_unqual Peter Eisentraut <[email protected]>
2026-03-07 00:17 ` Re: Change copyObject() to use typeof_unqual Jelte Fennema-Nio <[email protected]>
2026-03-13 10:43 ` Re: Change copyObject() to use typeof_unqual Peter Eisentraut <[email protected]>
2026-03-13 16:00 ` Re: Change copyObject() to use typeof_unqual Peter Eisentraut <[email protected]>
2026-03-13 16:15 ` Re: Change copyObject() to use typeof_unqual Jelte Fennema-Nio <[email protected]>
2026-03-13 16:18 ` Re: Change copyObject() to use typeof_unqual Jelte Fennema-Nio <[email protected]>
@ 2026-03-14 13:41 ` Jelte Fennema-Nio <[email protected]>
0 siblings, 0 replies; 26+ messages in thread
From: Jelte Fennema-Nio @ 2026-03-14 13:41 UTC (permalink / raw)
To: Peter Eisentraut <[email protected]>; +Cc: Daniel Gustafsson <[email protected]>; pgsql-hackers
On Sat, 14 Mar 2026 at 14:03, Peter Eisentraut <[email protected]> wrote:
> This doesn't appear to work in this example program:
Ugh, I should not send emails end of day on a friday in a rush.
Attached is fixed v3 which uses ::type instead.
I was able to reproduce the compilation errors on my machine by using
CXXFLAGS='-std=c++11' when configuring meson, and this patch fixes them.
I think it would be good if we would run one of our CI jobs in c11 and
c++11 (non-gnu) mode so we catch these kind of issues before hitting the
build farm.
Attachments:
[text/x-patch] v3-0001-Make-typeof-and-typeof_unqual-fallback-definition.patch (1.3K, ../../[email protected]/2-v3-0001-Make-typeof-and-typeof_unqual-fallback-definition.patch)
download | inline diff:
From d7acf4680fcfa81d0b046241ee5e36fd47f46b06 Mon Sep 17 00:00:00 2001
From: Jelte Fennema-Nio <[email protected]>
Date: Sat, 14 Mar 2026 14:33:07 +0100
Subject: [PATCH v3] Make typeof and typeof_unqual fallback definitions work on
C++11
These macros were unintentionally using C++14 features. This replaces
them with valid C++11 code.
Tested locally by compiling with -std=c++11 (which reproduced the
original issue).
---
src/include/c.h | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/include/c.h b/src/include/c.h
index 2aab74d8b0e..29fef2f54e1 100644
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -447,7 +447,7 @@ extern "C++"
#ifdef pg_cxx_typeof
#define typeof(x) pg_cxx_typeof(x)
#elif !defined(HAVE_CXX_TYPEOF)
-#define typeof(x) std::remove_reference_t<decltype(x)>
+#define typeof(x) std::remove_reference<decltype(x)>::type
#endif
#ifndef HAVE_TYPEOF
#define HAVE_TYPEOF 1
@@ -459,7 +459,7 @@ extern "C++"
#ifdef pg_cxx_typeof_unqual
#define typeof_unqual(x) pg_cxx_typeof_unqual(x)
#elif !defined(HAVE_CXX_TYPEOF_UNQUAL)
-#define typeof_unqual(x) std::remove_cv_t<std::remove_reference_t<decltype(x)>>
+#define typeof_unqual(x) std::remove_cv<std::remove_reference<decltype(x)>::type>::type
#endif
#ifndef HAVE_TYPEOF_UNQUAL
#define HAVE_TYPEOF_UNQUAL 1
base-commit: ae58189a4d523f0156ebe30f4534180555669e88
--
2.53.0
^ permalink raw reply [nested|flat] 26+ messages in thread
* Re: Change copyObject() to use typeof_unqual
2026-03-06 19:17 Re: Change copyObject() to use typeof_unqual Peter Eisentraut <[email protected]>
2026-03-07 00:17 ` Re: Change copyObject() to use typeof_unqual Jelte Fennema-Nio <[email protected]>
2026-03-13 10:43 ` Re: Change copyObject() to use typeof_unqual Peter Eisentraut <[email protected]>
@ 2026-03-15 21:54 ` Jelte Fennema-Nio <[email protected]>
2026-03-15 23:57 ` Re: Change copyObject() to use typeof_unqual Jelte Fennema-Nio <[email protected]>
1 sibling, 1 reply; 26+ messages in thread
From: Jelte Fennema-Nio @ 2026-03-15 21:54 UTC (permalink / raw)
To: Peter Eisentraut <[email protected]>; +Cc: pgsql-hackers
On Fri, 13 Mar 2026 at 11:43, Peter Eisentraut <[email protected]> wrote:
> There is a failure on buildfarm member taipan because it uses an unusual
> combination of gcc and clang (the gcc is much newer than clang). The
> only sensible workaround I could think of is a hardcoded override based
> on the clang version, as in the attached patch.
If we can then start prefering typeof_unqual over __typeof_unqual__ in
the configure check for CC, then I think I like this as a workaround.
If not, then I'm starting to think that actually checking support for
this feature for CLANG is probably easier to understand (and less
fragile) than combining all of these tricks together. Attached is a
patch to do so.
This only does it for CLANG, not for CLANG compiling C++ files.
Theoretically that could be necessary, but I couldn't find a C++
compiler that supports any spelling of typeof_unqual. So I'm not even
sure we need the current CXX check for typeof_unqual, I think we could
remove that too and always use the fallback.
> And alternative is that
> we decide that we don't want to support this combination, meaning that
> we would effectively require that clang is approximately as-old-or-newer
> than gcc.
Given that Tom seems to have reproduced this on Fedora 40, it sounds
like we should fix it.
Attachments:
[text/x-patch] v1-0001-Check-CLANG-for-typeof_unqual.patch (8.9K, ../../[email protected]/2-v1-0001-Check-CLANG-for-typeof_unqual.patch)
download | inline diff:
From 377b3b68c073c1b62bc0e5c357eed50624022cb5 Mon Sep 17 00:00:00 2001
From: Jelte Fennema-Nio <[email protected]>
Date: Sun, 15 Mar 2026 22:39:45 +0100
Subject: [PATCH v1] Check CLANG for typeof_unqual
Turns out that CLANG on the buildfarm is sometimes significantly older
than the CC compiler, and thus supports different features. This
explicitly checks typeof_unqual support for CLANG, because that's the
feature that sometimes seems to be lacking in practice.
---
config/c-compiler.m4 | 45 +++++++++++++++++++++-----
configure | 65 +++++++++++++++++++++++++++++++++-----
configure.ac | 6 ++++
src/include/c.h | 16 ++++++++++
src/include/pg_config.h.in | 7 ++++
5 files changed, 123 insertions(+), 16 deletions(-)
diff --git a/config/c-compiler.m4 b/config/c-compiler.m4
index 88333ef301d..6ae57199b1c 100644
--- a/config/c-compiler.m4
+++ b/config/c-compiler.m4
@@ -181,16 +181,12 @@ fi])# PGAC_C_TYPEOF
# Check if the C compiler understands typeof_unqual or a variant. Define
# HAVE_TYPEOF_UNQUAL if so, and define 'typeof_unqual' to the actual key word.
#
+# Test with a void pointer, because MSVC doesn't handle that, and we
+# need that for copyObject().
AC_DEFUN([PGAC_C_TYPEOF_UNQUAL],
[AC_CACHE_CHECK(for typeof_unqual, pgac_cv_c_typeof_unqual,
[pgac_cv_c_typeof_unqual=no
-# Test the underscore variant first so that there is a higher chance
-# that clang used for bitcode also supports it, since we don't test
-# that separately.
-#
-# Test with a void pointer, because MSVC doesn't handle that, and we
-# need that for copyObject().
-for pgac_kw in __typeof_unqual__ typeof_unqual; do
+for pgac_kw in typeof_unqual __typeof_unqual__; do
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],
[int x = 0;
$pgac_kw(x) y;
@@ -248,7 +244,7 @@ AC_DEFUN([PGAC_CXX_TYPEOF_UNQUAL],
[AC_CACHE_CHECK(for C++ typeof_unqual, pgac_cv_cxx_typeof_unqual,
[pgac_cv_cxx_typeof_unqual=no
AC_LANG_PUSH(C++)
-for pgac_kw in __typeof_unqual__ typeof_unqual; do
+for pgac_kw in typeof_unqual __typeof_unqual__; do
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],
[int x = 0;
$pgac_kw(x) y;
@@ -270,6 +266,39 @@ if test "$pgac_cv_cxx_typeof_unqual" != no; then
fi])# PGAC_CXX_TYPEOF_UNQUAL
+# PGAC_CLANG_TYPEOF_UNQUAL
+# ------------------------
+# Check if CLANG (used for LLVM bitcode compilation) understands
+# typeof_unqual or a variant. Define HAVE_CLANG_TYPEOF_UNQUAL if so, and
+# define 'pg_clang_typeof_unqual' to the actual key word.
+#
+AC_DEFUN([PGAC_CLANG_TYPEOF_UNQUAL],
+[AC_CACHE_CHECK(for CLANG typeof_unqual, pgac_cv_clang_typeof_unqual,
+[pgac_cv_clang_typeof_unqual=no
+pgac_save_CC=$CC
+CC="$CLANG"
+for pgac_kw in typeof_unqual __typeof_unqual__; do
+ _AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],
+[int x = 0;
+$pgac_kw(x) y;
+const void *a;
+void *b;
+y = x;
+b = ($pgac_kw(*a) *) a;
+return y;])],
+[pgac_cv_clang_typeof_unqual=$pgac_kw])
+ test "$pgac_cv_clang_typeof_unqual" != no && break
+done
+CC="$pgac_save_CC"])
+if test "$pgac_cv_clang_typeof_unqual" != no; then
+ AC_DEFINE(HAVE_CLANG_TYPEOF_UNQUAL, 1,
+ [Define to 1 if CLANG for bitcode understands `typeof_unqual' or something similar.])
+ if test "$pgac_cv_clang_typeof_unqual" != typeof_unqual; then
+ AC_DEFINE_UNQUOTED(pg_clang_typeof_unqual, $pgac_cv_clang_typeof_unqual, [Define to how CLANG for bitcode spells `typeof_unqual'.])
+ fi
+fi])# PGAC_CLANG_TYPEOF_UNQUAL
+
+
# PGAC_C_TYPES_COMPATIBLE
# -----------------------
diff --git a/configure b/configure
index 4c789bd9289..80e29ff3ead 100755
--- a/configure
+++ b/configure
@@ -7077,6 +7077,9 @@ fi
if test "$with_llvm" = yes ; then
CLANGXX="$CLANG -xc++"
+ BITCODE_CFLAGS="$BITCODE_CFLAGS -DPG_COMPILING_BITCODE"
+ BITCODE_CXXFLAGS="$BITCODE_CXXFLAGS -DPG_COMPILING_BITCODE"
+
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${CLANG} supports -fno-strict-aliasing, for BITCODE_CFLAGS" >&5
$as_echo_n "checking whether ${CLANG} supports -fno-strict-aliasing, for BITCODE_CFLAGS... " >&6; }
if ${pgac_cv_prog_CLANG_cflags__fno_strict_aliasing+:} false; then :
@@ -15107,13 +15110,7 @@ if ${pgac_cv_c_typeof_unqual+:} false; then :
$as_echo_n "(cached) " >&6
else
pgac_cv_c_typeof_unqual=no
-# Test the underscore variant first so that there is a higher chance
-# that clang used for bitcode also supports it, since we don't test
-# that separately.
-#
-# Test with a void pointer, because MSVC doesn't handle that, and we
-# need that for copyObject().
-for pgac_kw in __typeof_unqual__ typeof_unqual; do
+for pgac_kw in typeof_unqual __typeof_unqual__; do
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
@@ -15164,7 +15161,7 @@ ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
-for pgac_kw in __typeof_unqual__ typeof_unqual; do
+for pgac_kw in typeof_unqual __typeof_unqual__; do
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
@@ -15208,6 +15205,58 @@ cat >>confdefs.h <<_ACEOF
_ACEOF
fi
+fi
+if test "$with_llvm" = yes; then :
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for CLANG typeof_unqual" >&5
+$as_echo_n "checking for CLANG typeof_unqual... " >&6; }
+if ${pgac_cv_clang_typeof_unqual+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ pgac_cv_clang_typeof_unqual=no
+pgac_save_CC=$CC
+CC="$CLANG"
+for pgac_kw in typeof_unqual __typeof_unqual__; do
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+int x = 0;
+$pgac_kw(x) y;
+const void *a;
+void *b;
+y = x;
+b = ($pgac_kw(*a) *) a;
+return y;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ pgac_cv_clang_typeof_unqual=$pgac_kw
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ test "$pgac_cv_clang_typeof_unqual" != no && break
+done
+CC="$pgac_save_CC"
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $pgac_cv_clang_typeof_unqual" >&5
+$as_echo "$pgac_cv_clang_typeof_unqual" >&6; }
+if test "$pgac_cv_clang_typeof_unqual" != no; then
+
+$as_echo "#define HAVE_CLANG_TYPEOF_UNQUAL 1" >>confdefs.h
+
+ if test "$pgac_cv_clang_typeof_unqual" != typeof_unqual; then
+
+cat >>confdefs.h <<_ACEOF
+#define pg_clang_typeof_unqual $pgac_cv_clang_typeof_unqual
+_ACEOF
+
+ fi
+fi
+
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for __builtin_types_compatible_p" >&5
$as_echo_n "checking for __builtin_types_compatible_p... " >&6; }
diff --git a/configure.ac b/configure.ac
index 9edffe481a6..69ad014238f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -686,6 +686,9 @@ AC_SUBST(CXXFLAGS_SL_MODULE)
if test "$with_llvm" = yes ; then
CLANGXX="$CLANG -xc++"
+ BITCODE_CFLAGS="$BITCODE_CFLAGS -DPG_COMPILING_BITCODE"
+ BITCODE_CXXFLAGS="$BITCODE_CXXFLAGS -DPG_COMPILING_BITCODE"
+
PGAC_PROG_VARCC_VARFLAGS_OPT(CLANG, BITCODE_CFLAGS, [-fno-strict-aliasing])
PGAC_PROG_VARCXX_VARFLAGS_OPT(CLANGXX, BITCODE_CXXFLAGS, [-fno-strict-aliasing])
PGAC_PROG_VARCC_VARFLAGS_OPT(CLANG, BITCODE_CFLAGS, [-fwrapv])
@@ -1734,6 +1737,9 @@ PGAC_C_TYPEOF
PGAC_CXX_TYPEOF
PGAC_C_TYPEOF_UNQUAL
PGAC_CXX_TYPEOF_UNQUAL
+AS_IF([test "$with_llvm" = yes], [
+ PGAC_CLANG_TYPEOF_UNQUAL
+])
PGAC_C_TYPES_COMPATIBLE
PGAC_C_BUILTIN_CONSTANT_P
PGAC_C_BUILTIN_OP_OVERFLOW
diff --git a/src/include/c.h b/src/include/c.h
index 29fef2f54e1..e0dfb897529 100644
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -466,6 +466,22 @@ extern "C++"
#endif
#endif /* __cplusplus */
+/*
+ * Override typeof_unqual for LLVM bitcode compilation when CLANG doesn't
+ * support the same keyword as CC. Analogous to the C++ override above.
+ * PG_COMPILING_BITCODE is defined in BITCODE_CFLAGS.
+ */
+#if defined(PG_COMPILING_BITCODE) && !defined(__cplusplus)
+#undef HAVE_TYPEOF_UNQUAL
+#undef typeof_unqual
+#ifdef pg_clang_typeof_unqual
+#define typeof_unqual(x) pg_clang_typeof_unqual(x)
+#define HAVE_TYPEOF_UNQUAL 1
+#elif defined(HAVE_CLANG_TYPEOF_UNQUAL)
+#define HAVE_TYPEOF_UNQUAL 1
+#endif
+#endif /* PG_COMPILING_BITCODE && !__cplusplus */
+
/*
* CppAsString
* Convert the argument to a string, using the C preprocessor.
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in
index 79379a4d125..b1c20ce754a 100644
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -54,6 +54,10 @@
/* Define to 1 if you have the `backtrace_symbols' function. */
#undef HAVE_BACKTRACE_SYMBOLS
+/* Define to 1 if CLANG for bitcode understands `typeof_unqual' or something
+ similar. */
+#undef HAVE_CLANG_TYPEOF_UNQUAL
+
/* Define to 1 if your compiler handles computed gotos. */
#undef HAVE_COMPUTED_GOTO
@@ -789,6 +793,9 @@
/* Define for large files, on AIX-style hosts. */
#undef _LARGE_FILES
+/* Define to how CLANG for bitcode spells `typeof_unqual'. */
+#undef pg_clang_typeof_unqual
+
/* Define to how the C++ compiler spells `typeof'. */
#undef pg_cxx_typeof
base-commit: a793677e57bc27c674cb94b230164b2c28f4cbae
--
2.53.0
^ permalink raw reply [nested|flat] 26+ messages in thread
* Re: Change copyObject() to use typeof_unqual
2026-03-06 19:17 Re: Change copyObject() to use typeof_unqual Peter Eisentraut <[email protected]>
2026-03-07 00:17 ` Re: Change copyObject() to use typeof_unqual Jelte Fennema-Nio <[email protected]>
2026-03-13 10:43 ` Re: Change copyObject() to use typeof_unqual Peter Eisentraut <[email protected]>
2026-03-15 21:54 ` Re: Change copyObject() to use typeof_unqual Jelte Fennema-Nio <[email protected]>
@ 2026-03-15 23:57 ` Jelte Fennema-Nio <[email protected]>
2026-03-16 13:40 ` Re: Change copyObject() to use typeof_unqual Jelte Fennema-Nio <[email protected]>
0 siblings, 1 reply; 26+ messages in thread
From: Jelte Fennema-Nio @ 2026-03-15 23:57 UTC (permalink / raw)
To: Tom Lane <[email protected]>; +Cc: Peter Eisentraut <[email protected]>; pgsql-hackers
On Sun, 15 Mar 2026 at 23:13, Tom Lane <[email protected]> wrote:
>
> "Jelte Fennema-Nio" <[email protected]> writes:
> > If not, then I'm starting to think that actually checking support for
> > this feature for CLANG is probably easier to understand (and less
> > fragile) than combining all of these tricks together. Attached is a
> > patch to do so.
>
> +1 for concept, but don't you need to fix meson.build too?
I believe that we don't have fully working bc compilation for meson[1],
so I'm not entirely sure how to test out if it actually works. But the
attached now does *something* for meson too at least.
[1]: https://www.postgresql.org/message-id/flat/206b001d-1884-4081-bd02-bed5c92f02ba%40eisentraut.org
Attachments:
[text/x-patch] v2-0001-Check-CLANG-for-typeof_unqual.patch (12.1K, ../../[email protected]/2-v2-0001-Check-CLANG-for-typeof_unqual.patch)
download | inline diff:
From 2058a59b52b17ce15752b7f488082929967429c3 Mon Sep 17 00:00:00 2001
From: Jelte Fennema-Nio <[email protected]>
Date: Sun, 15 Mar 2026 22:39:45 +0100
Subject: [PATCH v2] Check CLANG for typeof_unqual
Turns out that CLANG on the buildfarm is sometimes significantly older
than the CC compiler, and thus supports different features. This
explicitly checks typeof_unqual support for CLANG, because that's the
feature that sometimes seems to be lacking in practice.
---
config/c-compiler.m4 | 45 ++++++++++++++++++----
config/test_typeof_unqual.c | 20 ++++++++++
configure | 65 ++++++++++++++++++++++++++++----
configure.ac | 6 +++
meson.build | 32 +++++++++++++---
src/backend/jit/llvm/meson.build | 2 +-
src/include/c.h | 16 ++++++++
src/include/pg_config.h.in | 7 ++++
8 files changed, 170 insertions(+), 23 deletions(-)
create mode 100644 config/test_typeof_unqual.c
diff --git a/config/c-compiler.m4 b/config/c-compiler.m4
index 88333ef301d..6ae57199b1c 100644
--- a/config/c-compiler.m4
+++ b/config/c-compiler.m4
@@ -181,16 +181,12 @@ fi])# PGAC_C_TYPEOF
# Check if the C compiler understands typeof_unqual or a variant. Define
# HAVE_TYPEOF_UNQUAL if so, and define 'typeof_unqual' to the actual key word.
#
+# Test with a void pointer, because MSVC doesn't handle that, and we
+# need that for copyObject().
AC_DEFUN([PGAC_C_TYPEOF_UNQUAL],
[AC_CACHE_CHECK(for typeof_unqual, pgac_cv_c_typeof_unqual,
[pgac_cv_c_typeof_unqual=no
-# Test the underscore variant first so that there is a higher chance
-# that clang used for bitcode also supports it, since we don't test
-# that separately.
-#
-# Test with a void pointer, because MSVC doesn't handle that, and we
-# need that for copyObject().
-for pgac_kw in __typeof_unqual__ typeof_unqual; do
+for pgac_kw in typeof_unqual __typeof_unqual__; do
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],
[int x = 0;
$pgac_kw(x) y;
@@ -248,7 +244,7 @@ AC_DEFUN([PGAC_CXX_TYPEOF_UNQUAL],
[AC_CACHE_CHECK(for C++ typeof_unqual, pgac_cv_cxx_typeof_unqual,
[pgac_cv_cxx_typeof_unqual=no
AC_LANG_PUSH(C++)
-for pgac_kw in __typeof_unqual__ typeof_unqual; do
+for pgac_kw in typeof_unqual __typeof_unqual__; do
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],
[int x = 0;
$pgac_kw(x) y;
@@ -270,6 +266,39 @@ if test "$pgac_cv_cxx_typeof_unqual" != no; then
fi])# PGAC_CXX_TYPEOF_UNQUAL
+# PGAC_CLANG_TYPEOF_UNQUAL
+# ------------------------
+# Check if CLANG (used for LLVM bitcode compilation) understands
+# typeof_unqual or a variant. Define HAVE_CLANG_TYPEOF_UNQUAL if so, and
+# define 'pg_clang_typeof_unqual' to the actual key word.
+#
+AC_DEFUN([PGAC_CLANG_TYPEOF_UNQUAL],
+[AC_CACHE_CHECK(for CLANG typeof_unqual, pgac_cv_clang_typeof_unqual,
+[pgac_cv_clang_typeof_unqual=no
+pgac_save_CC=$CC
+CC="$CLANG"
+for pgac_kw in typeof_unqual __typeof_unqual__; do
+ _AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],
+[int x = 0;
+$pgac_kw(x) y;
+const void *a;
+void *b;
+y = x;
+b = ($pgac_kw(*a) *) a;
+return y;])],
+[pgac_cv_clang_typeof_unqual=$pgac_kw])
+ test "$pgac_cv_clang_typeof_unqual" != no && break
+done
+CC="$pgac_save_CC"])
+if test "$pgac_cv_clang_typeof_unqual" != no; then
+ AC_DEFINE(HAVE_CLANG_TYPEOF_UNQUAL, 1,
+ [Define to 1 if CLANG for bitcode understands `typeof_unqual' or something similar.])
+ if test "$pgac_cv_clang_typeof_unqual" != typeof_unqual; then
+ AC_DEFINE_UNQUOTED(pg_clang_typeof_unqual, $pgac_cv_clang_typeof_unqual, [Define to how CLANG for bitcode spells `typeof_unqual'.])
+ fi
+fi])# PGAC_CLANG_TYPEOF_UNQUAL
+
+
# PGAC_C_TYPES_COMPATIBLE
# -----------------------
diff --git a/config/test_typeof_unqual.c b/config/test_typeof_unqual.c
new file mode 100644
index 00000000000..108c8f5468b
--- /dev/null
+++ b/config/test_typeof_unqual.c
@@ -0,0 +1,20 @@
+/*
+ * Test program for typeof_unqual detection.
+ *
+ * Used by meson.build to check whether clang used for LLVM bitcode
+ * compilation supports typeof_unqual or a variant. Pass -DKW=<keyword>
+ * to test a specific spelling.
+ */
+int
+main(void)
+{
+ int x = 0;
+
+ KW(x) y;
+ const void *a;
+ void *b;
+
+ y = x;
+ b = (KW(*a) *) a;
+ return y;
+}
diff --git a/configure b/configure
index 4c789bd9289..80e29ff3ead 100755
--- a/configure
+++ b/configure
@@ -7077,6 +7077,9 @@ fi
if test "$with_llvm" = yes ; then
CLANGXX="$CLANG -xc++"
+ BITCODE_CFLAGS="$BITCODE_CFLAGS -DPG_COMPILING_BITCODE"
+ BITCODE_CXXFLAGS="$BITCODE_CXXFLAGS -DPG_COMPILING_BITCODE"
+
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${CLANG} supports -fno-strict-aliasing, for BITCODE_CFLAGS" >&5
$as_echo_n "checking whether ${CLANG} supports -fno-strict-aliasing, for BITCODE_CFLAGS... " >&6; }
if ${pgac_cv_prog_CLANG_cflags__fno_strict_aliasing+:} false; then :
@@ -15107,13 +15110,7 @@ if ${pgac_cv_c_typeof_unqual+:} false; then :
$as_echo_n "(cached) " >&6
else
pgac_cv_c_typeof_unqual=no
-# Test the underscore variant first so that there is a higher chance
-# that clang used for bitcode also supports it, since we don't test
-# that separately.
-#
-# Test with a void pointer, because MSVC doesn't handle that, and we
-# need that for copyObject().
-for pgac_kw in __typeof_unqual__ typeof_unqual; do
+for pgac_kw in typeof_unqual __typeof_unqual__; do
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
@@ -15164,7 +15161,7 @@ ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
-for pgac_kw in __typeof_unqual__ typeof_unqual; do
+for pgac_kw in typeof_unqual __typeof_unqual__; do
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
@@ -15208,6 +15205,58 @@ cat >>confdefs.h <<_ACEOF
_ACEOF
fi
+fi
+if test "$with_llvm" = yes; then :
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for CLANG typeof_unqual" >&5
+$as_echo_n "checking for CLANG typeof_unqual... " >&6; }
+if ${pgac_cv_clang_typeof_unqual+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ pgac_cv_clang_typeof_unqual=no
+pgac_save_CC=$CC
+CC="$CLANG"
+for pgac_kw in typeof_unqual __typeof_unqual__; do
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+int x = 0;
+$pgac_kw(x) y;
+const void *a;
+void *b;
+y = x;
+b = ($pgac_kw(*a) *) a;
+return y;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ pgac_cv_clang_typeof_unqual=$pgac_kw
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ test "$pgac_cv_clang_typeof_unqual" != no && break
+done
+CC="$pgac_save_CC"
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $pgac_cv_clang_typeof_unqual" >&5
+$as_echo "$pgac_cv_clang_typeof_unqual" >&6; }
+if test "$pgac_cv_clang_typeof_unqual" != no; then
+
+$as_echo "#define HAVE_CLANG_TYPEOF_UNQUAL 1" >>confdefs.h
+
+ if test "$pgac_cv_clang_typeof_unqual" != typeof_unqual; then
+
+cat >>confdefs.h <<_ACEOF
+#define pg_clang_typeof_unqual $pgac_cv_clang_typeof_unqual
+_ACEOF
+
+ fi
+fi
+
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for __builtin_types_compatible_p" >&5
$as_echo_n "checking for __builtin_types_compatible_p... " >&6; }
diff --git a/configure.ac b/configure.ac
index 9edffe481a6..69ad014238f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -686,6 +686,9 @@ AC_SUBST(CXXFLAGS_SL_MODULE)
if test "$with_llvm" = yes ; then
CLANGXX="$CLANG -xc++"
+ BITCODE_CFLAGS="$BITCODE_CFLAGS -DPG_COMPILING_BITCODE"
+ BITCODE_CXXFLAGS="$BITCODE_CXXFLAGS -DPG_COMPILING_BITCODE"
+
PGAC_PROG_VARCC_VARFLAGS_OPT(CLANG, BITCODE_CFLAGS, [-fno-strict-aliasing])
PGAC_PROG_VARCXX_VARFLAGS_OPT(CLANGXX, BITCODE_CXXFLAGS, [-fno-strict-aliasing])
PGAC_PROG_VARCC_VARFLAGS_OPT(CLANG, BITCODE_CFLAGS, [-fwrapv])
@@ -1734,6 +1737,9 @@ PGAC_C_TYPEOF
PGAC_CXX_TYPEOF
PGAC_C_TYPEOF_UNQUAL
PGAC_CXX_TYPEOF_UNQUAL
+AS_IF([test "$with_llvm" = yes], [
+ PGAC_CLANG_TYPEOF_UNQUAL
+])
PGAC_C_TYPES_COMPATIBLE
PGAC_C_BUILTIN_CONSTANT_P
PGAC_C_BUILTIN_OP_OVERFLOW
diff --git a/meson.build b/meson.build
index f7a87edcc94..f17970f1ae2 100644
--- a/meson.build
+++ b/meson.build
@@ -2969,13 +2969,9 @@ endif
# Check if the C compiler understands typeof_unqual or a variant. Define
# HAVE_TYPEOF_UNQUAL if so, and define 'typeof_unqual' to the actual key word.
#
-# Test the underscore variant first so that there is a higher chance
-# that clang used for bitcode also supports it, since we don't test
-# that separately.
-#
# Test with a void pointer, because MSVC doesn't handle that, and we
# need that for copyObject().
-foreach kw : ['__typeof_unqual__', 'typeof_unqual']
+foreach kw : ['typeof_unqual', '__typeof_unqual__']
if cc.compiles('''
int main(void)
{
@@ -3002,7 +2998,7 @@ endforeach
# Check if the C++ compiler understands typeof_unqual or a variant.
if have_cxx
- foreach kw : ['__typeof_unqual__', 'typeof_unqual']
+ foreach kw : ['typeof_unqual', '__typeof_unqual__']
if cxx.compiles('''
int main(void)
{
@@ -3028,6 +3024,30 @@ int main(void)
endforeach
endif
+# Check if CLANG (used for LLVM bitcode compilation) understands
+# typeof_unqual or a variant. We use run_command with a test file
+# because clang is a program, not a meson compiler object, so
+# cc.compiles() cannot be used.
+if llvm.found()
+ clang_typeof_unqual_found = false
+ foreach kw : ['typeof_unqual', '__typeof_unqual__']
+ if not clang_typeof_unqual_found
+ r = run_command(clang, '-fsyntax-only', '-DKW=' + kw,
+ files('config/test_typeof_unqual.c'), check: false)
+ if r.returncode() == 0
+ message('CLANG supports ' + kw)
+ clang_typeof_unqual_found = true
+ cdata.set('HAVE_CLANG_TYPEOF_UNQUAL', 1)
+ if kw != 'typeof_unqual'
+ cdata.set('pg_clang_typeof_unqual', kw)
+ endif
+ else
+ message('CLANG does not support ' + kw)
+ endif
+ endif
+ endforeach
+endif
+
# MSVC doesn't cope well with defining restrict to __restrict, the
# spelling it understands, because it conflicts with
diff --git a/src/backend/jit/llvm/meson.build b/src/backend/jit/llvm/meson.build
index 7df8453ad6f..7270143771e 100644
--- a/src/backend/jit/llvm/meson.build
+++ b/src/backend/jit/llvm/meson.build
@@ -60,7 +60,7 @@ endif
# XXX: Need to determine proper version of the function cflags for clang
-bitcode_cflags = ['-fno-strict-aliasing', '-fwrapv']
+bitcode_cflags = ['-DPG_COMPILING_BITCODE', '-fno-strict-aliasing', '-fwrapv']
bitcode_cflags += get_option('c_args')
bitcode_cflags += cppflags
diff --git a/src/include/c.h b/src/include/c.h
index 29fef2f54e1..e0dfb897529 100644
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -466,6 +466,22 @@ extern "C++"
#endif
#endif /* __cplusplus */
+/*
+ * Override typeof_unqual for LLVM bitcode compilation when CLANG doesn't
+ * support the same keyword as CC. Analogous to the C++ override above.
+ * PG_COMPILING_BITCODE is defined in BITCODE_CFLAGS.
+ */
+#if defined(PG_COMPILING_BITCODE) && !defined(__cplusplus)
+#undef HAVE_TYPEOF_UNQUAL
+#undef typeof_unqual
+#ifdef pg_clang_typeof_unqual
+#define typeof_unqual(x) pg_clang_typeof_unqual(x)
+#define HAVE_TYPEOF_UNQUAL 1
+#elif defined(HAVE_CLANG_TYPEOF_UNQUAL)
+#define HAVE_TYPEOF_UNQUAL 1
+#endif
+#endif /* PG_COMPILING_BITCODE && !__cplusplus */
+
/*
* CppAsString
* Convert the argument to a string, using the C preprocessor.
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in
index 79379a4d125..b1c20ce754a 100644
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -54,6 +54,10 @@
/* Define to 1 if you have the `backtrace_symbols' function. */
#undef HAVE_BACKTRACE_SYMBOLS
+/* Define to 1 if CLANG for bitcode understands `typeof_unqual' or something
+ similar. */
+#undef HAVE_CLANG_TYPEOF_UNQUAL
+
/* Define to 1 if your compiler handles computed gotos. */
#undef HAVE_COMPUTED_GOTO
@@ -789,6 +793,9 @@
/* Define for large files, on AIX-style hosts. */
#undef _LARGE_FILES
+/* Define to how CLANG for bitcode spells `typeof_unqual'. */
+#undef pg_clang_typeof_unqual
+
/* Define to how the C++ compiler spells `typeof'. */
#undef pg_cxx_typeof
base-commit: a793677e57bc27c674cb94b230164b2c28f4cbae
--
2.53.0
^ permalink raw reply [nested|flat] 26+ messages in thread
* Re: Change copyObject() to use typeof_unqual
2026-03-06 19:17 Re: Change copyObject() to use typeof_unqual Peter Eisentraut <[email protected]>
2026-03-07 00:17 ` Re: Change copyObject() to use typeof_unqual Jelte Fennema-Nio <[email protected]>
2026-03-13 10:43 ` Re: Change copyObject() to use typeof_unqual Peter Eisentraut <[email protected]>
2026-03-15 21:54 ` Re: Change copyObject() to use typeof_unqual Jelte Fennema-Nio <[email protected]>
2026-03-15 23:57 ` Re: Change copyObject() to use typeof_unqual Jelte Fennema-Nio <[email protected]>
@ 2026-03-16 13:40 ` Jelte Fennema-Nio <[email protected]>
2026-03-16 22:28 ` Re: Change copyObject() to use typeof_unqual Masahiko Sawada <[email protected]>
0 siblings, 1 reply; 26+ messages in thread
From: Jelte Fennema-Nio @ 2026-03-16 13:40 UTC (permalink / raw)
To: Peter Eisentraut <[email protected]>; +Cc: Tom Lane <[email protected]>; pgsql-hackers
On Mon, 16 Mar 2026 at 13:47, Peter Eisentraut <[email protected]> wrote:
> I'm tempted to go with my proposed patch of a version-based override for
> the time being.
Sounds good to me. But let's not forget to swap back the order of
detection for typeof_unqual vs __typeof_unqual__. Afaict that's not
needed anymore and the comment there only becomes confusing with this
new fix.
Also, it might be nice to only do your version based override, if
we're actually compiling bitcode. In my patch I used
-DPG_COMPILING_BITCODE for that. Otherwise this override can also
happen for regular compiles using clang, which I think would be a bit
confusing.
^ permalink raw reply [nested|flat] 26+ messages in thread
* Re: Change copyObject() to use typeof_unqual
2026-03-06 19:17 Re: Change copyObject() to use typeof_unqual Peter Eisentraut <[email protected]>
2026-03-07 00:17 ` Re: Change copyObject() to use typeof_unqual Jelte Fennema-Nio <[email protected]>
2026-03-13 10:43 ` Re: Change copyObject() to use typeof_unqual Peter Eisentraut <[email protected]>
2026-03-15 21:54 ` Re: Change copyObject() to use typeof_unqual Jelte Fennema-Nio <[email protected]>
2026-03-15 23:57 ` Re: Change copyObject() to use typeof_unqual Jelte Fennema-Nio <[email protected]>
2026-03-16 13:40 ` Re: Change copyObject() to use typeof_unqual Jelte Fennema-Nio <[email protected]>
@ 2026-03-16 22:28 ` Masahiko Sawada <[email protected]>
2026-03-17 10:56 ` Re: Change copyObject() to use typeof_unqual Jelte Fennema-Nio <[email protected]>
0 siblings, 1 reply; 26+ messages in thread
From: Masahiko Sawada @ 2026-03-16 22:28 UTC (permalink / raw)
To: Tom Lane <[email protected]>; +Cc: Jelte Fennema-Nio <[email protected]>; Peter Eisentraut <[email protected]>; pgsql-hackers
Hi,
On Mon, Mar 16, 2026 at 8:32 AM Tom Lane <[email protected]> wrote:
>
> Jelte Fennema-Nio <[email protected]> writes:
> > On Mon, 16 Mar 2026 at 13:47, Peter Eisentraut <[email protected]> wrote:
> >> I'm tempted to go with my proposed patch of a version-based override for
> >> the time being.
>
> > Sounds good to me.
>
> I confirmed that Peter's
> 0001-Hardcode-override-of-typeof_unqual-for-clang-for-bit.patch
> fixes the problem on my Fedora 40 system.
I'm still encountering the following error while building from source
at commit f4af7849b3d when using autoconf:
execParallel.c:154:9: error: call to undeclared function
'typeof_unqual'; ISO C99 and later do not support implicit function
declarations [-Wimplicit-function-declaration]
154 | plan = copyObject(plan);
| ^
../../../src/include/nodes/nodes.h:230:27: note: expanded from macro
'copyObject'
230 | #define copyObject(obj) ((typeof_unqual(*(obj)) *) copyObjectImpl(obj))
| ^
execParallel.c:154:9: error: expected expression
../../../src/include/nodes/nodes.h:230:50: note: expanded from macro
'copyObject'
230 | #define copyObject(obj) ((typeof_unqual(*(obj)) *) copyObjectImpl(obj))
| ^
analyze.c:3213:27: error: call to undeclared function 'typeof_unqual';
ISO C99 and later do not support implicit function declarations
[-Wimplicit-function-declaration]
3213 | stmt->into->viewQuery = copyObject(query);
| ^
../../../src/include/nodes/nodes.h:230:27: note: expanded from macro
'copyObject'
230 | #define copyObject(obj) ((typeof_unqual(*(obj)) *) copyObjectImpl(obj))
| ^
analyze.c:3213:27: error: expected expression
../../../src/include/nodes/nodes.h:230:50: note: expanded from macro
'copyObject'
230 | #define copyObject(obj) ((typeof_unqual(*(obj)) *) copyObjectImpl(obj))
| ^
2 errors generated.
:
(many similar errors)
I'm using Fedora 43 and gcc (GCC) 15.2.1 20260123 (Red Hat 15.2.1-7).
The issue doesn't happen when using meson+ninja.
Regards,
--
Masahiko Sawada
Amazon Web Services: https://aws.amazon.com
^ permalink raw reply [nested|flat] 26+ messages in thread
* Re: Change copyObject() to use typeof_unqual
2026-03-06 19:17 Re: Change copyObject() to use typeof_unqual Peter Eisentraut <[email protected]>
2026-03-07 00:17 ` Re: Change copyObject() to use typeof_unqual Jelte Fennema-Nio <[email protected]>
2026-03-13 10:43 ` Re: Change copyObject() to use typeof_unqual Peter Eisentraut <[email protected]>
2026-03-15 21:54 ` Re: Change copyObject() to use typeof_unqual Jelte Fennema-Nio <[email protected]>
2026-03-15 23:57 ` Re: Change copyObject() to use typeof_unqual Jelte Fennema-Nio <[email protected]>
2026-03-16 13:40 ` Re: Change copyObject() to use typeof_unqual Jelte Fennema-Nio <[email protected]>
2026-03-16 22:28 ` Re: Change copyObject() to use typeof_unqual Masahiko Sawada <[email protected]>
@ 2026-03-17 10:56 ` Jelte Fennema-Nio <[email protected]>
0 siblings, 0 replies; 26+ messages in thread
From: Jelte Fennema-Nio @ 2026-03-17 10:56 UTC (permalink / raw)
To: Tom Lane <[email protected]>; Masahiko Sawada <[email protected]>; +Cc: Peter Eisentraut <[email protected]>; pgsql-hackers
On Tue Mar 17, 2026 at 3:39 AM CET, Tom Lane wrote:
> While this version of clang doesn't like typeof_unqual, it does take
> __typeof_unqual__. So maybe we were premature to decide that we
> could prefer the typeof_unqual spelling.
Hmmm, that makes sense. How about this patch to at least keep the
all the logic related to this in one place? I was able to reproduce this
error using the following flags, and this fixes the issue for me.
CC=clang-21 CXX=clang++-21 CFLAGS=-std=c23 BITCODE_CFLAGS=-std=gnu17 CLANG=clang-19 LLVM_CONFIG=llvm-config-19
Attachments:
[text/x-patch] v1-0001-Hardcode-typeof_unqual-to-__typeof_unqual__-for-c.patch (1.0K, ../../[email protected]/2-v1-0001-Hardcode-typeof_unqual-to-__typeof_unqual__-for-c.patch)
download | inline diff:
From b0261abce45ff144bc6f8c9d797984f8377fcfe0 Mon Sep 17 00:00:00 2001
From: Jelte Fennema-Nio <[email protected]>
Date: Tue, 17 Mar 2026 11:34:16 +0100
Subject: [PATCH v1] Hardcode typeof_unqual to __typeof_unqual__ for clang
A new attempt was made in 63275ce84d2 to make typeof_unqual work on all
configurations of CC and CLANG. This re-introduced an old problem
though, where CLANG would only support __typeof_unqual__ but the
configure check for CC detected support for typeof_unqual.
This fixes that by always defining typeof_unqual as __typeof_unqual__
under clang.
---
src/include/c.h | 3 +++
1 file changed, 3 insertions(+)
diff --git a/src/include/c.h b/src/include/c.h
index 8987a121d6a..fd6b093bb3a 100644
--- a/src/include/c.h
+++ b/src/include/c.h
@@ -444,6 +444,9 @@ extern "C++"
#if defined(__clang__)
#if __clang_major__ < 19
#undef HAVE_TYPEOF_UNQUAL
+#else
+#undef typeof_unqual
+#define typeof_unqual __typeof_unqual__
#endif
#endif /* __clang__ */
base-commit: 182cdf5aeaf7b34a288a135d66f2893dc288a24e
--
2.53.0
^ permalink raw reply [nested|flat] 26+ messages in thread
* Re: Change copyObject() to use typeof_unqual
2026-03-06 19:17 Re: Change copyObject() to use typeof_unqual Peter Eisentraut <[email protected]>
@ 2026-06-13 12:14 ` Álvaro Herrera <[email protected]>
2026-06-13 15:56 ` Re: Change copyObject() to use typeof_unqual Tom Lane <[email protected]>
1 sibling, 1 reply; 26+ messages in thread
From: Álvaro Herrera @ 2026-06-13 12:14 UTC (permalink / raw)
To: Peter Eisentraut <[email protected]>; +Cc: pgsql-hackers; Jelte Fennema-Nio <[email protected]>
On 2026-Mar-06, Peter Eisentraut wrote:
> From f2f750f7c3ab6b73514ab2fd5f02185abe9ad59f Mon Sep 17 00:00:00 2001
> From: Peter Eisentraut <[email protected]>
> Date: Fri, 6 Mar 2026 13:31:01 +0100
> Subject: [PATCH v2 1/3] Fixes for C++ typeof implementation
>
> This fixes two bugs in commit 1887d822f14.
>
> First, if we are using the fallback C++ implementation of typeof, then
> we need to include the C++ header <type_traits> for
> std::remove_reference_t. This header is also likely to be used for
> other C++ implementations of type tricks, so we'll put it into the
> global includes.
For some reason, a couple of animals running gcc-15 or newer
(leafhopper, massasauga, parula) appear to be failing now because of
this.
ccache gcc -Wall -Wmissing-prototypes -Wpointer-arith -Wdeclaration-after-statement -Werror=vla -Wmissing-format-attribute -Wold-style-declaration -Wimplicit-fallthrough=5 -Wcast-function-type -Wshadow=compatible-local -Wformat-security -Wmissing-variable-declarations -fno-strict-aliasing -fwrapv -fexcess-precision=standard -Wno-format-truncation -Wno-stringop-truncation -g -O2 -Wstrict-prototypes -Wold-style-definition -fPIC -fvisibility=hidden -shared -o test_slru.so test_slru.o test_multixact.o -L../../../../src/port -L../../../../src/common -Wl,--as-needed -Wl,-rpath,'/home/bf/proj/bf/build-farm-17/HEAD/inst/lib',--enable-new-dtags -fvisibility=hidden
In file included from ../../../../src/include/postgres.h:48,
from test_cplusplusext.cpp:18:
../../../../src/include/c.h:91:10: fatal error: type_traits: No such file or directory
91 | #include <type_traits>
| ^~~~~~~~~~~~~
compilation terminated.
make[1]: *** [<builtin>: test_cplusplusext.o] Error 1
make[1]: Leaving directory '/home/bf/proj/bf/build-farm-17/HEAD/pgsql.build/src/test/modules/test_cplusplusext'
--
Álvaro Herrera Breisgau, Deutschland — https://www.EnterpriseDB.com/
^ permalink raw reply [nested|flat] 26+ messages in thread
* Re: Change copyObject() to use typeof_unqual
2026-03-06 19:17 Re: Change copyObject() to use typeof_unqual Peter Eisentraut <[email protected]>
2026-06-13 12:14 ` Re: Change copyObject() to use typeof_unqual Álvaro Herrera <[email protected]>
@ 2026-06-13 15:56 ` Tom Lane <[email protected]>
2026-06-17 11:45 ` Re: Change copyObject() to use typeof_unqual Robins Tharakan <[email protected]>
0 siblings, 1 reply; 26+ messages in thread
From: Tom Lane @ 2026-06-13 15:56 UTC (permalink / raw)
To: Álvaro Herrera <[email protected]>; +Cc: Peter Eisentraut <[email protected]>; pgsql-hackers; Jelte Fennema-Nio <[email protected]>; [email protected]
=?utf-8?Q?=C3=81lvaro?= Herrera <[email protected]> writes:
> For some reason, a couple of animals running gcc-15 or newer
> (leafhopper, massasauga, parula) appear to be failing now because of
> this.
They just started failing a day or two ago, so it's hard to blame
it on any code change we made. I see that all three of those animals
are using "experimental" nightly builds of gcc, so it's reasonable to
assume that gcc's git tip is broken. Or maybe something needs updated
in the recipe for replacing their gcc builds.
regards, tom lane
^ permalink raw reply [nested|flat] 26+ messages in thread
* Re: Change copyObject() to use typeof_unqual
2026-03-06 19:17 Re: Change copyObject() to use typeof_unqual Peter Eisentraut <[email protected]>
2026-06-13 12:14 ` Re: Change copyObject() to use typeof_unqual Álvaro Herrera <[email protected]>
2026-06-13 15:56 ` Re: Change copyObject() to use typeof_unqual Tom Lane <[email protected]>
@ 2026-06-17 11:45 ` Robins Tharakan <[email protected]>
2026-06-17 12:11 ` Re: Change copyObject() to use typeof_unqual Jelte Fennema-Nio <[email protected]>
0 siblings, 1 reply; 26+ messages in thread
From: Robins Tharakan @ 2026-06-17 11:45 UTC (permalink / raw)
To: Tom Lane <[email protected]>; +Cc: Álvaro Herrera <[email protected]>; Peter Eisentraut <[email protected]>; pgsql-hackers; Jelte Fennema-Nio <[email protected]>; [email protected]
Hi,
On Sun, 14 Jun 2026 at 01:27, Tom Lane <[email protected]> wrote:
>
> =?utf-8?Q?=C3=81lvaro?= Herrera <[email protected]> writes:
> > For some reason, a couple of animals running gcc-15 or newer
> > (leafhopper, massasauga, parula) appear to be failing now because of
> > this.
>
> They just started failing a day or two ago, so it's hard to blame
> it on any code change we made. I see that all three of those animals
> are using "experimental" nightly builds of gcc, so it's reasonable to
> assume that gcc's git tip is broken. Or maybe something needs updated
> in the recipe for replacing their gcc builds.
Earlier, since gcc HEAD was too noisy, I moved them all to gcc v15
assuming it'd be better. The gcc build script has been stable and there's
been no change in any of the machines recently, so I also wouldn't be
surprised if it is gcc again.
For now, I've taken them all offline and unless someone has a better
idea, I'll switch them to stay pinned to the recentmost gcc release
version - rationale being that if a tagged gcc release is buggy, it
may be interesting to know about.
-
robins | robins.in
^ permalink raw reply [nested|flat] 26+ messages in thread
* Re: Change copyObject() to use typeof_unqual
2026-03-06 19:17 Re: Change copyObject() to use typeof_unqual Peter Eisentraut <[email protected]>
2026-06-13 12:14 ` Re: Change copyObject() to use typeof_unqual Álvaro Herrera <[email protected]>
2026-06-13 15:56 ` Re: Change copyObject() to use typeof_unqual Tom Lane <[email protected]>
2026-06-17 11:45 ` Re: Change copyObject() to use typeof_unqual Robins Tharakan <[email protected]>
@ 2026-06-17 12:11 ` Jelte Fennema-Nio <[email protected]>
0 siblings, 0 replies; 26+ messages in thread
From: Jelte Fennema-Nio @ 2026-06-17 12:11 UTC (permalink / raw)
To: Robins Tharakan <[email protected]>; +Cc: Tom Lane <[email protected]>; Álvaro Herrera <[email protected]>; Peter Eisentraut <[email protected]>; pgsql-hackers; [email protected]
On Wed, 17 Jun 2026 at 13:46, Robins Tharakan <[email protected]> wrote:
> Earlier, since gcc HEAD was too noisy, I moved them all to gcc v15
> assuming it'd be better. The gcc build script has been stable and there's
> been no change in any of the machines recently, so I also wouldn't be
> surprised if it is gcc again.
>
> For now, I've taken them all offline and unless someone has a better
> idea, I'll switch them to stay pinned to the recentmost gcc release
> version - rationale being that if a tagged gcc release is buggy, it
> may be interesting to know about.
FWIW the error that alvaro mentions suggests that either the C++
stdlib was not installed (i.e. some installation/configuration
problem) or that extern "C++" {...} is broken.
^ permalink raw reply [nested|flat] 26+ messages in thread
end of thread, other threads:[~2026-06-17 12:11 UTC | newest]
Thread overview: 26+ messages (download: mbox mbox.gz follow: Atom feed)
-- links below jump to the message on this page --
2022-07-01 02:38 [PATCH 1/2] Use permanent backup-abort call back in perform_base_backup Kyotaro Horiguchi <[email protected]>
2022-07-01 02:38 [PATCH v2] Use permanent backup-abort call back in perform_base_backup Kyotaro Horiguchi <[email protected]>
2023-08-02 06:01 Re: Extract numeric filed in JSONB more effectively jian he <[email protected]>
2023-08-03 00:50 ` Re: Extract numeric filed in JSONB more effectively Andy Fan <[email protected]>
2023-08-03 04:59 ` Re: Extract numeric filed in JSONB more effectively Pavel Stehule <[email protected]>
2023-08-03 07:53 ` Re: Extract numeric filed in JSONB more effectively Andy Fan <[email protected]>
2023-08-03 09:47 ` Re: Extract numeric filed in JSONB more effectively Pavel Stehule <[email protected]>
2023-08-03 13:22 ` Re: Extract numeric filed in JSONB more effectively Andy Fan <[email protected]>
2023-08-03 12:34 ` Re: Extract numeric filed in JSONB more effectively Chapman Flack <[email protected]>
2023-08-03 13:50 ` Re: Extract numeric filed in JSONB more effectively Andy Fan <[email protected]>
2026-03-06 19:17 Re: Change copyObject() to use typeof_unqual Peter Eisentraut <[email protected]>
2026-03-07 00:17 ` Re: Change copyObject() to use typeof_unqual Jelte Fennema-Nio <[email protected]>
2026-03-13 10:43 ` Re: Change copyObject() to use typeof_unqual Peter Eisentraut <[email protected]>
2026-03-13 16:00 ` Re: Change copyObject() to use typeof_unqual Peter Eisentraut <[email protected]>
2026-03-13 16:15 ` Re: Change copyObject() to use typeof_unqual Jelte Fennema-Nio <[email protected]>
2026-03-13 16:18 ` Re: Change copyObject() to use typeof_unqual Jelte Fennema-Nio <[email protected]>
2026-03-14 13:41 ` Re: Change copyObject() to use typeof_unqual Jelte Fennema-Nio <[email protected]>
2026-03-15 21:54 ` Re: Change copyObject() to use typeof_unqual Jelte Fennema-Nio <[email protected]>
2026-03-15 23:57 ` Re: Change copyObject() to use typeof_unqual Jelte Fennema-Nio <[email protected]>
2026-03-16 13:40 ` Re: Change copyObject() to use typeof_unqual Jelte Fennema-Nio <[email protected]>
2026-03-16 22:28 ` Re: Change copyObject() to use typeof_unqual Masahiko Sawada <[email protected]>
2026-03-17 10:56 ` Re: Change copyObject() to use typeof_unqual Jelte Fennema-Nio <[email protected]>
2026-06-13 12:14 ` Re: Change copyObject() to use typeof_unqual Álvaro Herrera <[email protected]>
2026-06-13 15:56 ` Re: Change copyObject() to use typeof_unqual Tom Lane <[email protected]>
2026-06-17 11:45 ` Re: Change copyObject() to use typeof_unqual Robins Tharakan <[email protected]>
2026-06-17 12:11 ` Re: Change copyObject() to use typeof_unqual Jelte Fennema-Nio <[email protected]>
This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox