Skip to content

Commit dcf077f

Browse files
authored
planner: add equals function generation logic for logical operator. (#57057)
ref #51664
1 parent 5448f9f commit dcf077f

File tree

3 files changed

+97
-49
lines changed

3 files changed

+97
-49
lines changed

pkg/planner/core/generator/hash64_equals/hash64_equals_generator.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ var hashEqualsType = reflect.TypeOf((*base.HashEquals)(nil)).Elem()
5252
func genHash64EqualsForLogicalOps(x any) ([]byte, error) {
5353
c := new(cc)
5454
vType := reflect.TypeOf(x)
55+
// for Hash64 function.
5556
c.write("// Hash64 implements the Hash64Equals interface.")
5657
c.write("func (op *%v) Hash64(h base.Hasher) {", vType.Name())
5758
c.write("h.HashString(%v)", logicalOpName2PlanCodecString(vType.Name()))
@@ -72,6 +73,23 @@ func genHash64EqualsForLogicalOps(x any) ([]byte, error) {
7273
}
7374
}
7475
c.write("}")
76+
// for Equals function.
77+
c.write("// Equals implements the Hash64Equals interface, only receive *%v pointer.", vType.Name())
78+
c.write("func (op *%v) Equals(other any) bool {", vType.Name())
79+
c.write("if other == nil { return false }")
80+
c.write("op2, ok := other.(*%v)", vType.Name())
81+
c.write("if !ok { return false }")
82+
for i := 0; i < vType.NumField(); i++ {
83+
f := vType.Field(i)
84+
if !isHash64EqualsField(f) {
85+
continue
86+
}
87+
leftCallName := "op." + vType.Field(i).Name
88+
rightCallName := "op2." + vType.Field(i).Name
89+
c.EqualsElement(f.Type, leftCallName, rightCallName)
90+
}
91+
c.write("return true")
92+
c.write("}")
7593
return c.format()
7694
}
7795

@@ -88,6 +106,30 @@ func isHash64EqualsField(fType reflect.StructField) bool {
88106
return fType.Tag.Get("hash64-equals") == "true"
89107
}
90108

109+
// EqualsElement EqualsElements generate the equals function for every field inside logical op.
110+
func (c *cc) EqualsElement(fType reflect.Type, lhs, rhs string) {
111+
switch fType.Kind() {
112+
case reflect.Slice:
113+
c.write("if len(%v) != len(%v) { return false }", lhs, rhs)
114+
c.write("for i, one := range %v {", lhs)
115+
// one more round
116+
c.EqualsElement(fType.Elem(), "one", rhs+"[i]")
117+
c.write("}")
118+
case reflect.String, reflect.Bool, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
119+
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Float32, reflect.Float64:
120+
c.write("if %v != %v {return false}", lhs, rhs)
121+
default:
122+
if fType.Implements(hashEqualsType) {
123+
if fType.Kind() == reflect.Struct {
124+
rhs = "&" + rhs
125+
}
126+
c.write("if !%v.Equals(%v) {return false}", lhs, rhs)
127+
} else {
128+
panic("doesn't support element type" + fType.Kind().String())
129+
}
130+
}
131+
}
132+
91133
func (c *cc) Hash64Element(fType reflect.Type, callName string) {
92134
switch fType.Kind() {
93135
case reflect.Slice:

pkg/planner/core/operator/logicalop/hash64_equals_generated.go

Lines changed: 55 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/planner/core/operator/logicalop/logical_join.go

Lines changed: 0 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -150,55 +150,6 @@ func (p LogicalJoin) Init(ctx base.PlanContext, offset int) *LogicalJoin {
150150
return &p
151151
}
152152

153-
// ************************ start implementation of HashEquals interface ************************
154-
155-
// Equals implements the HashEquals.<1st> interface.
156-
func (p *LogicalJoin) Equals(other any) bool {
157-
if other == nil {
158-
return false
159-
}
160-
var p2 *LogicalJoin
161-
switch x := other.(type) {
162-
case *LogicalJoin:
163-
p2 = x
164-
case LogicalJoin:
165-
p2 = &x
166-
default:
167-
return false
168-
}
169-
ok := p.JoinType != p2.JoinType && len(p.EqualConditions) == len(p2.EqualConditions) && len(p.NAEQConditions) == len(p2.NAEQConditions) &&
170-
len(p.LeftConditions) == len(p2.LeftConditions) && len(p.RightConditions) == len(p2.RightConditions) && len(p.OtherConditions) == len(p2.OtherConditions)
171-
if !ok {
172-
return false
173-
}
174-
for i, oneCond := range p.EqualConditions {
175-
if !oneCond.Equals(p2.EqualConditions[i]) {
176-
return false
177-
}
178-
}
179-
for i, oneCond := range p.NAEQConditions {
180-
if !oneCond.Equals(p2.NAEQConditions[i]) {
181-
return false
182-
}
183-
}
184-
for i, oneCond := range p.LeftConditions {
185-
if !oneCond.Equals(p2.LeftConditions[i]) {
186-
return false
187-
}
188-
}
189-
for i, oneCond := range p.RightConditions {
190-
if !oneCond.Equals(p2.RightConditions[i]) {
191-
return false
192-
}
193-
}
194-
for i, oneCond := range p.OtherConditions {
195-
if !oneCond.Equals(p2.OtherConditions[i]) {
196-
return false
197-
}
198-
}
199-
return true
200-
}
201-
202153
// *************************** start implementation of Plan interface ***************************
203154

204155
// ExplainInfo implements Plan interface.

0 commit comments

Comments
 (0)