Skip to content

Commit 6a55648

Browse files
mkindahlCommitfest Bot
authored and
Commitfest Bot
committed
Semantic patch for pg_cmp_* functions
In commit 3b42bdb and 6b80394 overflow-safe comparison functions where introduced, but they are not widely used. This semantic patch identifies some of the more common cases and replaces them with calls to the corresponding pg_cmp_* function.
1 parent c7f0fa4 commit 6a55648

File tree

1 file changed

+125
-0
lines changed

1 file changed

+125
-0
lines changed

cocci/use_pg_cmp.cocci

+125
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
// Find cases where we can use the new pg_cmp_* functions.
2+
//
3+
// Copyright 2025 Mats Kindahl, Timescale.
4+
//
5+
// Options: --no-includes --include-headers
6+
7+
virtual report
8+
virtual context
9+
virtual patch
10+
11+
@initialize:python@
12+
@@
13+
14+
import re
15+
16+
TYPMAP = {
17+
'BlockNumber': 'pg_cmp_u32',
18+
'ForkNumber': 'pg_cmp_s32',
19+
'OffsetNumber': 'pg_cmp_s16',
20+
'int': 'pg_cmp_s32',
21+
'int16': 'pg_cmp_s16',
22+
'int32': 'pg_cmp_s32',
23+
'uint16': 'pg_cmp_u16',
24+
'uint32': 'pg_cmp_u32',
25+
'unsigned int': 'pg_cmp_u32',
26+
}
27+
28+
def is_valid(expr):
29+
return not re.search(r'DatumGet[A-Za-z]+', expr)
30+
31+
@r1e depends on context || report expression@
32+
type TypeName : script:python() { TypeName in TYPMAP };
33+
position pos;
34+
TypeName lhs : script:python() { is_valid(lhs) };
35+
TypeName rhs : script:python() { is_valid(rhs) };
36+
@@
37+
* lhs@pos < rhs ? -1 : lhs > rhs ? 1 : 0
38+
39+
@script:python depends on report@
40+
lhs << r1e.lhs;
41+
rhs << r1e.rhs;
42+
pos << r1e.pos;
43+
@@
44+
coccilib.report.print_report(pos[0], f"conditional checks between '{lhs}' and '{rhs}' can be replaced with a PostgreSQL comparison function")
45+
46+
@r1 depends on context || report@
47+
type TypeName : script:python() { TypeName in TYPMAP };
48+
position pos;
49+
TypeName lhs : script:python() { is_valid(lhs) };
50+
TypeName rhs : script:python() { is_valid(rhs) };
51+
@@
52+
(
53+
* if@pos (lhs < rhs) return -1; else if (lhs > rhs) return 1; return 0;
54+
|
55+
* if@pos (lhs < rhs) return -1; else if (lhs > rhs) return 1; else return 0;
56+
|
57+
* if@pos (lhs < rhs) return -1; if (lhs > rhs) return 1; return 0;
58+
|
59+
* if@pos (lhs > rhs) return 1; if (lhs < rhs) return -1; return 0;
60+
|
61+
* if@pos (lhs == rhs) return 0; if (lhs > rhs) return 1; return -1;
62+
|
63+
* if@pos (lhs == rhs) return 0; return lhs > rhs ? 1 : -1;
64+
|
65+
* if@pos (lhs == rhs) return 0; return lhs < rhs ? -1 : 1;
66+
)
67+
68+
@script:python depends on report@
69+
lhs << r1.lhs;
70+
rhs << r1.rhs;
71+
pos << r1.pos;
72+
@@
73+
coccilib.report.print_report(pos[0], f"conditional checks between '{lhs}' and '{rhs}' can be replaced with a PostgreSQL comparison function")
74+
75+
@expr_repl depends on patch expression@
76+
type TypeName : script:python() { TypeName in TYPMAP };
77+
fresh identifier cmp = script:python(TypeName) { TYPMAP[TypeName] };
78+
TypeName lhs : script:python() { is_valid(lhs) };
79+
TypeName rhs : script:python() { is_valid(rhs) };
80+
@@
81+
- lhs < rhs ? -1 : lhs > rhs ? 1 : 0
82+
+ cmp(lhs,rhs)
83+
84+
@stmt_repl depends on patch@
85+
type TypeName : script:python() { TypeName in TYPMAP };
86+
fresh identifier cmp = script:python(TypeName) { TYPMAP[TypeName] };
87+
TypeName lhs : script:python() { is_valid(lhs) };
88+
TypeName rhs : script:python() { is_valid(rhs) };
89+
@@
90+
(
91+
- if (lhs < rhs) return -1; if (lhs > rhs) return 1; return 0;
92+
+ return cmp(lhs,rhs);
93+
|
94+
- if (lhs < rhs) return -1; else if (lhs > rhs) return 1; return 0;
95+
+ return cmp(lhs,rhs);
96+
|
97+
- if (lhs < rhs) return -1; else if (lhs > rhs) return 1; else return 0;
98+
+ return cmp(lhs,rhs);
99+
|
100+
- if (lhs > rhs) return 1; if (lhs < rhs) return -1; return 0;
101+
+ return cmp(lhs,rhs);
102+
|
103+
- if (lhs > rhs) return 1; else if (lhs < rhs) return -1; return 0;
104+
+ return cmp(lhs,rhs);
105+
|
106+
- if (lhs == rhs) return 0; if (lhs > rhs) return 1; return -1;
107+
+ return cmp(lhs,rhs);
108+
|
109+
- if (lhs == rhs) return 0; return lhs > rhs ? 1 : -1;
110+
+ return cmp(lhs,rhs);
111+
|
112+
- if (lhs == rhs) return 0; return lhs < rhs ? -1 : 1;
113+
+ return cmp(lhs,rhs);
114+
)
115+
116+
// Add an include if there were none and we had to do some
117+
// replacements
118+
@has_include depends on patch@
119+
@@
120+
#include "common/int.h"
121+
122+
@depends on patch && !has_include && (stmt_repl || expr_repl)@
123+
@@
124+
#include ...
125+
+ #include "common/int.h"

0 commit comments

Comments
 (0)