@@ -6,6 +6,7 @@ package issues
66import (
77 "context"
88 "fmt"
9+ "strconv"
910 "strings"
1011
1112 "code.gitea.io/gitea/models/db"
@@ -130,17 +131,30 @@ func applyLabelsCondition(sess *xorm.Session, opts *IssuesOptions) *xorm.Session
130131 if opts .LabelIDs [0 ] == 0 {
131132 sess .Where ("issue.id NOT IN (SELECT issue_id FROM issue_label)" )
132133 } else {
133- // We deduplicate the ID to reduce the load the database
134- // (possible DoS here by multiplying the joins )
135- uniqueLabelIDs := container .SetOf ( opts . LabelIDs ... ). Values ( )
136- for i , labelID := range uniqueLabelIDs {
134+ // We sort and deduplicate the labels' ids
135+ IncludedLabelIDs := make (container. Set [ int64 ] )
136+ ExcludedLabelIDs := make ( container.Set [ int64 ] )
137+ for _ , labelID := range opts . LabelIDs {
137138 if labelID > 0 {
138- sess .Join ("INNER" , fmt .Sprintf ("issue_label il%d" , i ),
139- fmt .Sprintf ("issue.id = il%[1]d.issue_id AND il%[1]d.label_id = %[2]d" , i , labelID ))
139+ IncludedLabelIDs .Add (labelID )
140140 } else if labelID < 0 { // 0 is not supported here, so just ignore it
141- sess . Where ( "issue.id not in (select issue_id from issue_label where label_id = ?)" , - labelID )
141+ ExcludedLabelIDs . Add ( - labelID )
142142 }
143143 }
144+ // ... and use them in a subquery of the form :
145+ // where (select count(*) from issue_label where issue_id=issue.id and label_id in (2, 4, 6)) = 3
146+ // This equality is garanteed thanks to unique index (issue_id,label_id) on table issue_label.
147+ if (len (IncludedLabelIDs ) > 0 ) {
148+ subquery := builder .Select ("count(*)" ).From ("issue_label" ).Where (builder .Expr ("issue_id = issue.id" )).
149+ And (builder .In ("label_id" , IncludedLabelIDs .Values ()))
150+ sess .Where (builder.Eq {strconv .Itoa (len (IncludedLabelIDs )): subquery })
151+ }
152+ // or (select count(*)...) = 0 for excluded labels
153+ if (len (ExcludedLabelIDs ) > 0 ) {
154+ subquery := builder .Select ("count(*)" ).From ("issue_label" ).Where (builder .Expr ("issue_id = issue.id" )).
155+ And (builder .In ("label_id" , ExcludedLabelIDs .Values ()))
156+ sess .Where (builder.Eq {"0" : subquery })
157+ }
144158 }
145159 }
146160
0 commit comments