Skip to content

Commit 48ea0e2

Browse files
committed
fixes #1576
1 parent d5f349d commit 48ea0e2

File tree

4 files changed

+170
-74
lines changed

4 files changed

+170
-74
lines changed

src/main/java/net/sf/jsqlparser/util/cnfexpression/CNFConverter.java

Lines changed: 32 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,6 @@ public class CNFConverter {
213213
// notice temp1 will be settled as the root and temp2 will be
214214
// settled as the dummy root.
215215
private boolean isUsed = false;
216-
private CloneHelper clone = new CloneHelper();
217216

218217
private class Mule {
219218

@@ -234,9 +233,8 @@ public static Expression convertToCNF(Expression expr) {
234233
}
235234

236235
/**
237-
* this method takes an expression tree and converts that into a CNF form. Notice the 5 steps
238-
* shown above will turn into 5 different methods. For the sake of testing, I set them public.
239-
* return the converted expression.
236+
* this method takes an expression tree and converts that into a CNF form. Notice the 5 steps shown above will turn
237+
* into 5 different methods. For the sake of testing, I set them public. return the converted expression.
240238
*
241239
* @param express the original expression tree.
242240
*/
@@ -260,21 +258,21 @@ private Expression convert(Expression express)
260258
}
261259

262260
/**
263-
* this is the first step that rebuild the expression tree. Use the standard specified in the
264-
* above class. Traverse the original tree recursively and rebuild the tree from that.
261+
* this is the first step that rebuild the expression tree. Use the standard specified in the above class. Traverse
262+
* the original tree recursively and rebuild the tree from that.
265263
*
266264
* @param express the original expression tree.
267265
*/
268266
private void reorder(Expression express) {
269-
root = clone.modify(express);
267+
root = CloneHelper.modify(express);
270268
List<Expression> list = new ArrayList<Expression>();
271269
list.add(root);
272270
dummy = new MultiAndExpression(list);
273271
}
274272

275273
/**
276-
* This method is used to deal with pushing not operators down. Since it needs an extra
277-
* parameter, I will create a new method to handle this.
274+
* This method is used to deal with pushing not operators down. Since it needs an extra parameter, I will create a
275+
* new method to handle this.
278276
*/
279277
private void pushNotDown() {
280278
/* set the two temp parameters to their staring point. */
@@ -290,11 +288,10 @@ private void pushNotDown() {
290288
}
291289

292290
/**
293-
* This method is the helper function to push not operators down. traverse the tree thoroughly,
294-
* when we meet the not operator. We only need to consider these three operators:
295-
* MultiAndOperator, MultiOrOperator, NotOperator. Handle them in a seperate way. when we finish
296-
* the traverse, the expression tree will have all the not operators pushed as downwards as they
297-
* could. In the method, I use two global variables: temp1 and temp2 to traverse the expression
291+
* This method is the helper function to push not operators down. traverse the tree thoroughly, when we meet the not
292+
* operator. We only need to consider these three operators: MultiAndOperator, MultiOrOperator, NotOperator. Handle
293+
* them in a seperate way. when we finish the traverse, the expression tree will have all the not operators pushed
294+
* as downwards as they could. In the method, I use two global variables: temp1 and temp2 to traverse the expression
298295
* tree. Notice that temp2 will always be the parent of temp1.
299296
*
300297
* @param index the index of the children appeared in parents array.
@@ -322,8 +319,8 @@ private void pushNot(int index) {
322319
}
323320

324321
/**
325-
* This function mainly deals with pushing not operators down. check the child. If it is not a
326-
* logic operator(and or or). stop at that point. Else use De Morgan law to push not downwards.
322+
* This function mainly deals with pushing not operators down. check the child. If it is not a logic operator(and or
323+
* or). stop at that point. Else use De Morgan law to push not downwards.
327324
*
328325
* @param index the index of the children appeared in parents array.
329326
*/
@@ -386,10 +383,9 @@ private void handleNot(int index) {
386383
}
387384

388385
/**
389-
* This method serves as dealing with the third step. It is used to put all the adjacent same
390-
* multi operators together. BFS the tree and do it node by node. In the end we will get the
391-
* tree where all the same multi operators store in the same odd level of the tree or in the
392-
* same even level of the tree.
386+
* This method serves as dealing with the third step. It is used to put all the adjacent same multi operators
387+
* together. BFS the tree and do it node by node. In the end we will get the tree where all the same multi operators
388+
* store in the same odd level of the tree or in the same even level of the tree.
393389
*/
394390
@SuppressWarnings({"PMD.CyclomaticComplexity"})
395391
private void gather() {
@@ -468,10 +464,10 @@ private void gather() {
468464
}
469465

470466
/**
471-
* First, BFS the tree and gather all the or operators and their parents into a stack. Next, pop
472-
* them out and push the and operators under the or operators upwards(if there are). Do this
473-
* level by level, which means during each level we will call the gather() method to make the
474-
* tree uniform. When we move out of the stack. The expression tree shall be in CNF form.
467+
* First, BFS the tree and gather all the or operators and their parents into a stack. Next, pop them out and push
468+
* the and operators under the or operators upwards(if there are). Do this level by level, which means during each
469+
* level we will call the gather() method to make the tree uniform. When we move out of the stack. The expression
470+
* tree shall be in CNF form.
475471
*/
476472
private void pushAndUp() {
477473
Queue<Mule> queue = new LinkedList<Mule>();
@@ -517,12 +513,11 @@ private void pushAndUp() {
517513
}
518514

519515
/**
520-
* This helper function is used to deal with pushing and up: generally, pop the top element out
521-
* of the stack, use BFS to traverse the tree and push and up. It will case the expression tree
522-
* to have the and as the new root and multiple or as the children. Push them on the queue and
523-
* repeat the same process until the newly generated or operator does not have any and operators
524-
* in it(which means no elements will be added into the queue). when one level is finished,
525-
* regroup the tree. Do this until the stack is empty, the result will be the expression in CNF
516+
* This helper function is used to deal with pushing and up: generally, pop the top element out of the stack, use
517+
* BFS to traverse the tree and push and up. It will case the expression tree to have the and as the new root and
518+
* multiple or as the children. Push them on the queue and repeat the same process until the newly generated or
519+
* operator does not have any and operators in it(which means no elements will be added into the queue). when one
520+
* level is finished, regroup the tree. Do this until the stack is empty, the result will be the expression in CNF
526521
* form.
527522
*
528523
* @param stack the stack stores a list of combined data.
@@ -570,7 +565,7 @@ private void pushAnd(Stack<Mule> stack) {
570565
MultiAndExpression newand = new MultiAndExpression(list);
571566
parents.setChild(parents.getIndex(children), newand);
572567
for (int i = 0; i < and.size(); i++) {
573-
Expression temp = clone.shallowCopy(children);
568+
Expression temp = CloneHelper.shallowCopy(children);
574569
MultipleExpression mtemp = (MultipleExpression) temp;
575570
mtemp.addChild(mtemp.size(), and.getChild(i));
576571
newand.addChild(i, mtemp);
@@ -581,21 +576,20 @@ private void pushAnd(Stack<Mule> stack) {
581576
}
582577

583578
/**
584-
* This is the final step of the CNF conversion: now we have the Expression tree that has one
585-
* multiple and expression with a list of multiple or expression as the child. So we need to
586-
* convert the multiple expression back to the binary counterparts. Note the converted tree is
587-
* left inclined. Also I attach a parenthesis node before the or expression that is attached to
588-
* the and expression to make the generated result resembles the CNF form.
579+
* This is the final step of the CNF conversion: now we have the Expression tree that has one multiple and
580+
* expression with a list of multiple or expression as the child. So we need to convert the multiple expression back
581+
* to the binary counterparts. Note the converted tree is left inclined. Also I attach a parenthesis node before the
582+
* or expression that is attached to the and expression to make the generated result resembles the CNF form.
589583
*/
590584
private void changeBack() {
591585
if (!(root instanceof MultiAndExpression)) {
592586
return;
593587
}
594588
MultipleExpression temp = (MultipleExpression) root;
595589
for (int i = 0; i < temp.size(); i++) {
596-
temp.setChild(i, clone.changeBack(true, temp.getChild(i)));
590+
temp.setChild(i, CloneHelper.changeBack(true, temp.getChild(i)));
597591
}
598-
root = clone.changeBack(false, temp);
592+
root = CloneHelper.changeBack(false, temp);
599593
}
600594

601595
}

src/main/java/net/sf/jsqlparser/util/cnfexpression/CloneHelper.java

Lines changed: 46 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,16 @@
1818
import net.sf.jsqlparser.expression.operators.conditional.OrExpression;
1919

2020
/**
21-
* This class is mainly used for handling the cloning of an expression tree.
22-
* Note this is the shallow copy of the tree. That means I do not modify
23-
* or copy the expression other than these expressions:
24-
* AND, OR, NOT, (), MULTI-AND, MULTI-OR.
25-
* Since the CNF conversion only change the condition part of the tree.
21+
* This class is mainly used for handling the cloning of an expression tree. Note this is the shallow copy of the tree.
22+
* That means I do not modify or copy the expression other than these expressions: AND, OR, NOT, (), MULTI-AND,
23+
* MULTI-OR. Since the CNF conversion only change the condition part of the tree.
2624
*
2725
* @author messfish
2826
*
2927
*/
3028
class CloneHelper {
3129

32-
public Expression modify(Expression express) {
30+
public static Expression modify(Expression express) {
3331
if (express instanceof NotExpression) {
3432
return new NotExpression(modify(((NotExpression) express).getExpression()));
3533
}
@@ -40,7 +38,7 @@ public Expression modify(Expression express) {
4038
}
4139
if (express instanceof AndExpression) {
4240
AndExpression and = (AndExpression) express;
43-
List<Expression> list = new ArrayList<Expression>();
41+
List<Expression> list = new ArrayList<>();
4442
list.add(modify(and.getLeftExpression()));
4543
list.add(modify(and.getRightExpression()));
4644
MultiAndExpression result = new MultiAndExpression(list);
@@ -51,7 +49,7 @@ public Expression modify(Expression express) {
5149
}
5250
if (express instanceof OrExpression) {
5351
OrExpression or = (OrExpression) express;
54-
List<Expression> list = new ArrayList<Expression>();
52+
List<Expression> list = new ArrayList<>();
5553
list.add(modify(or.getLeftExpression()));
5654
list.add(modify(or.getRightExpression()));
5755
MultiOrExpression result = new MultiOrExpression(list);
@@ -71,16 +69,16 @@ public Expression modify(Expression express) {
7169
}
7270

7371
/**
74-
* This method is used to copy the expression which happens at step four. I only copy the
75-
* conditional expressions since the CNF only changes the conditional part.
72+
* This method is used to copy the expression which happens at step four. I only copy the conditional expressions
73+
* since the CNF only changes the conditional part.
7674
*
7775
* @param express the expression that will be copied.
7876
* @return the copied expression.
7977
*/
80-
public Expression shallowCopy(Expression express) {
78+
public static Expression shallowCopy(Expression express) {
8179
if (express instanceof MultipleExpression) {
8280
MultipleExpression multi = (MultipleExpression) express;
83-
List<Expression> list = new ArrayList<Expression>();
81+
List<Expression> list = new ArrayList<>();
8482
for (int i = 0; i < multi.size(); i++) {
8583
list.add(shallowCopy(multi.getChild(i)));
8684
}
@@ -95,32 +93,54 @@ public Expression shallowCopy(Expression express) {
9593
}
9694

9795
/**
98-
* This helper method is used to change the multiple expression into the binary form,
99-
* respectively and return the root of the expression tree.
96+
* This helper method is used to change the multiple expression into the binary form, respectively and return the
97+
* root of the expression tree.
10098
*
10199
* @param isMultiOr variable tells whether the expression is or.
102100
* @param exp the expression that needs to be converted.
103101
* @return the root of the expression tree.
104102
*/
105-
public Expression changeBack(Boolean isMultiOr, Expression exp) {
103+
public static Expression changeBack(Boolean isMultiOr, Expression exp) {
106104
if (!(exp instanceof MultipleExpression)) {
107105
return exp;
108106
}
109-
MultipleExpression changed = (MultipleExpression) exp;
110-
Expression result = changed.getChild(0);
111-
for (int i = 1; i < changed.size(); i++) {
112-
Expression left = result;
113-
Expression right = changed.getChild(i);
114-
if (isMultiOr) {
115-
result = new OrExpression(left, right);
116-
} else {
117-
result = new AndExpression(left, right);
107+
108+
List<Expression> result = ((MultipleExpression) exp).getList();
109+
while (result.size() > 1) {
110+
List<Expression> compressed = new ArrayList<>();
111+
for (int i = 0; i < result.size(); i = i + 2) {
112+
Expression left = result.get(i);
113+
Expression right = i + 1 < result.size() ? result.get(i + 1) : null;
114+
115+
if (isMultiOr) {
116+
compressed.add(right != null ? new OrExpression(left, right) : left);
117+
} else {
118+
compressed.add(right != null ? new AndExpression(left, right) : left);
119+
}
118120
}
121+
result = compressed;
119122
}
120123
if (isMultiOr) {
121-
return new Parenthesis(result);
124+
return new Parenthesis(result.get(0));
125+
} else {
126+
return result.get(0);
122127
}
123-
return result;
128+
129+
// MultipleExpression changed = (MultipleExpression) exp;
130+
// Expression result = changed.getChild(0);
131+
// for (int i = 1; i < changed.size(); i++) {
132+
// Expression left = result;
133+
// Expression right = changed.getChild(i);
134+
// if (isMultiOr) {
135+
// result = new OrExpression(left, right);
136+
// } else {
137+
// result = new AndExpression(left, right);
138+
// }
139+
// }
140+
// if (isMultiOr) {
141+
// return new Parenthesis(result);
142+
// }
143+
// return result;
124144
}
125145

126146
}

0 commit comments

Comments
 (0)