You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@turbine.apache.org by Sam Joseph <ga...@yha.att.ne.jp> on 2002/04/25 05:27:31 UTC

[PATCH] Revised Criteria Patch

Following some comments from James Taylor (thanks James), I rewote the 
Criteria code patch to include as much documentation as possible and 
also reduce line length to under 80 characters where possible.

I hope that this will help with acceptance of this patch which supports 
two things.

1.  It makes the PeersHowTo documentation correct by allowing proper 
arbitrary depth nesting of "or" and "and" clauses
2.  It adds a parseCriterionString and parseCriterion methods to 
Criteria that allows a String representation of a Criterion object to be 
transformed back into a Criterion Object.

Point 1 is supported without making any changes to Criteria, and at the 
same time maintaining all existing Criterion methods in their current 
form.  

I hope very much you will consider using this patch, as I think a number 
of people have been caught out by the failure of Criterion to handle 
arbitrary depth nested "and" and "or" statements.  If point 2 is not 
considered necessary or just bad code, then  please let me know and I 
can submit a patch that supports just point 1 above, which is the most 
important after all.

Apologies for my multiple submissions of this patch, but this is the 
first time I have submitted a patch to an open source project and I am 
only gradually working out how to do this.

Index: src/java/org/apache/torque/util/Criteria.java
===================================================================
RCS file: 
/home/cvspublic/jakarta-turbine-torque/src/java/org/apache/torque/util/Criteria.java,v
retrieving revision 1.20
diff -u -r1.20 Criteria.java
--- src/java/org/apache/torque/util/Criteria.java    10 Apr 2002 
19:41:54 -0000    1.20
+++ src/java/org/apache/torque/util/Criteria.java    25 Apr 2002 
03:14:12 -0000
@@ -3200,6 +3200,264 @@
         blobFlag = (b ? Boolean.TRUE: Boolean.FALSE);
     }
 
+    private Hashtable x_clause_table = new Hashtable();
+
+    /**
+     * This function takes a string representation of multiple Criterions
+     * and turns it into a set of nested criterion objects
+     *
+     * @param p_criterion_string     Criterion String representation we 
want to parse
+     * @return Criterion             Criterion object containing all 
sub Criterion objects
+     */
+    public Criterion parseCriterionString(String p_criterion_string)
+      throws Exception
+    {
+        // find the first closing bracket
+        int x_first_close = p_criterion_string.indexOf(')');
+        if(x_first_close == -1) throw new Exception("no closing brace");
+        int x_latest = -1;
+        int x_matching_open = 0;
+       
+        // find the opening bracket in front of the closing bracket
+       
+        while(x_matching_open < x_first_close && x_matching_open != -1)
+        {
+          x_latest = x_matching_open;   
+          x_matching_open = p_criterion_string.indexOf('(',x_latest+1);
+
+        }
+        if(x_latest == -1) throw new Exception("no opening brace");
+       
+        // extract the internal criterion pair in between the brackets
+       
+          String x_pair = 
p_criterion_string.substring(x_latest+1,x_first_close);
+        boolean x_or = false;
+       
+        // work out what kind of clause it is
+       
+        int x_connector_start = x_pair.indexOf(Criterion.AND);
+        int x_connector_end = -1;
+        if(x_connector_start == -1)
+        {
+          x_or = true;
+          x_connector_start = x_pair.indexOf(Criterion.OR);
+          if(x_connector_start == -1)
+            throw new Exception("no connecting element: " + x_pair);
+          x_connector_end = x_connector_start + Criterion.OR.length();
+        }
+        else
+          x_connector_end = x_connector_start + Criterion.AND.length();
+         
+        // work out start position of former criterion 
+       
+        char x_char = '?';
+        int x_former_start = x_latest;
+        int x_incrementer = x_latest;
+        while(x_char == '?')
+        {
+          x_char = p_criterion_string.charAt(++x_incrementer);
+      x_former_start++;
+        }
+       
+        // see if we have already parsed this criterion or not
+       
+        Integer x_position = new Integer(x_former_start);
+        Criterion x_former = (Criterion)(x_clause_table.get(x_position));
+        if(x_former == null)
+        {
+          x_former = parseCriterion(x_pair.substring(0,x_connector_start));
+          x_clause_table.put(x_position,x_former);
+        }
+       
+        // see if we have already parsed the latter criterion or not
+       
+        x_position = new Integer(x_latest+1+x_connector_end+1);
+          Criterion x_latter = (Criterion)(x_clause_table.get(x_position));
+        if(x_latter == null)
+        {
+          x_latter = parseCriterion(x_pair.substring(x_connector_end));
+          x_clause_table.put(x_position,x_latter);
+        }
+        
+        Vector x_v = null;
+       
+        if(x_or == true)
+          x_former.or(x_latter);
+        else
+          x_former.and(x_latter);
+         
+        // now take original string and remove latter Criterion
+       
+        char[] x_array = new char[p_criterion_string.length()];
+         
+        p_criterion_string.getChars(0, x_latest, x_array, 0);
+        x_array[x_latest] = '?';
+       
+        int x_end_former = x_latest+1+x_connector_start;
+        
+        
p_criterion_string.getChars(x_latest+1,x_end_former,x_array,x_latest+1);
+        for(int i=x_latest+1+x_connector_start+1;i<x_first_close+1;i++)
+          x_array[i] = '?';
+         
+        int x_end_string = p_criterion_string.length();
+        int x_end_pair = x_first_close+1;
+        p_criterion_string.getChars(x_end_pair, x_end_string, x_array, 
x_end_pair);
+        String x_new_string = new String(x_array);
+        if(x_new_string.indexOf('(') == -1 && x_new_string.indexOf(')') 
== -1)
+          return x_former;  // if the remaining string has no brackets 
return criterion
+        else
+          return parseCriterionString(x_new_string); // otherwise delve 
deeper
+    }
+   
+    /**
+     * This function takes in a string representation of a single 
Criterion with
+     * no brackets, and returns a Criterion object for that string
+     *
+     *@param p_criterion_string       Criterion string representation
+     *@return Criterion               the corresponding Criterion object
+     */
+    public Criterion parseCriterion(String p_criterion_string)
+      throws Exception
+    {
+        String x_table = null;
+       
+        // find the dot marking the end of the table name
+       
+        int x_end_table = p_criterion_string.indexOf('.');
+        if(x_end_table!=-1)
+          x_table = p_criterion_string.substring(0,x_end_table);
+       
+        SqlEnum x_sql_enum = EQUAL;
+       
+        // determine what kind of comparator is being used
+        // apologies for heavy nesting here
+        // any suggestions for improvement gratefully recieved
+       
+        int x_end_column = p_criterion_string.indexOf(EQUAL.toString());
+        if(x_end_column==-1)
+        {
+          x_end_column = p_criterion_string.indexOf(NOT_EQUAL.toString());
+          if(x_end_column==-1)
+          {
+            x_end_column = 
p_criterion_string.indexOf(ALT_NOT_EQUAL.toString());
+            if(x_end_column==-1)
+            {
+              x_end_column = 
p_criterion_string.indexOf(GREATER_THAN.toString());
+              if(x_end_column==-1)
+              {
+                x_end_column = 
p_criterion_string.indexOf(LESS_THAN.toString());
+                if(x_end_column==-1)
+                {
+                  x_end_column = 
p_criterion_string.indexOf(GREATER_EQUAL.toString());
+                  if(x_end_column==-1)
+                  {
+                    x_end_column = 
p_criterion_string.indexOf(LESS_EQUAL.toString());
+                    if(x_end_column==-1)
+                    {
+                      x_end_column = 
p_criterion_string.indexOf(LIKE.toString());
+                      if(x_end_column==-1)
+                      {
+                        x_end_column = 
p_criterion_string.indexOf(NOT_LIKE.toString());
+                        if(x_end_column==-1)
+                        {
+                          x_end_column = 
p_criterion_string.indexOf(IN.toString());
+                          if(x_end_column==-1)
+                          {
+                            x_end_column = 
p_criterion_string.indexOf(NOT_IN.toString());
+                            if(x_end_column==-1)
+                            {
+                              x_end_column = 
p_criterion_string.indexOf(ISNULL.toString());
+                              if(x_end_column==-1)
+                              {
+                                x_end_column = 
p_criterion_string.indexOf(ISNOTNULL.toString());
+                                if(x_end_column==-1)      
+                                {
+                                  throw new Exception("No recognised 
comparator in this criterion: "
+                                                       + 
p_criterion_string.toString());
+                                }
+                                else
+                                  x_sql_enum = ISNOTNULL;    
+                              }
+                              else
+                              {
+                                x_sql_enum = ISNULL;
+                              }
+                            }
+                            else
+                            {
+                              x_sql_enum = NOT_IN;
+                            }
+                          }
+                          else
+                          {
+                            x_sql_enum = IN;
+                          }
+                        }
+                        else
+                        {
+                          x_sql_enum = NOT_LIKE;
+                        }
+                      }
+                      else
+                      {
+                        x_sql_enum = LIKE;
+                      }
+                    }
+                    else
+                    {
+                      x_sql_enum = LESS_EQUAL; 
+                    }             
+                  }
+                  else
+                  {
+                    x_sql_enum = GREATER_EQUAL;              
+                  }
+                }
+                else
+                {
+                  x_sql_enum = LESS_THAN;
+                }
+              }
+              else
+              {
+                x_sql_enum = GREATER_THAN;
+              }
+            }
+            else
+            {
+              x_sql_enum = ALT_NOT_EQUAL;
+            }
+          }
+          else
+          {
+            x_sql_enum = NOT_EQUAL;
+          }
+        }
+        else
+        {
+          x_sql_enum = EQUAL;
+        }
+       
+        // extract the various components
+       
+        if(x_end_table == -1) x_end_table++;
+        String x_column = 
p_criterion_string.substring(x_end_table+1,x_end_column);
+        String x_value = 
p_criterion_string.substring(x_end_column+x_sql_enum.toString().length());
+        x_value = x_value.replace('\'',' ');
+        x_value = x_value.trim();
+       
+        // try and create the Criterion object
+       
+        Criterion x_criterion = null;
+        if(x_table != null)
+          x_criterion = new 
Criterion(x_table,x_column,(Object)(x_value),x_sql_enum);
+        else
+          x_criterion = new 
Criterion(x_column,(Object)(x_value),x_sql_enum);
+         
+        return x_criterion;
+    }
+
+
     /**
      * This is an inner class that describes an object in the
      * criteria.
@@ -3217,6 +3475,7 @@
 
         /** Table name. */
         private String table;
+       
 
         /** Column name. */
         private String column;
@@ -3233,14 +3492,20 @@
         /**
          * Another Criterion connected to this one by an OR clause.
          */
-        private Criterion or;
+        //private Criterion or;
 
         /**
          * Another criterion connected to this one by an AND clause.
          */
-        private Criterion and;
+        //private Criterion and;
 
         /**
+         * other connected criteria and their types.
+         */
+        private Vector clauses = new Vector();
+        private Vector types = new Vector();
+       
+        /**
          * Creates a new instance, initializing a couple members.
          */
         private Criterion( Object val, SqlEnum comp )
@@ -3412,13 +3677,10 @@
         public void setDB(DB  v)
         {
             this.db = v;
-            if ( and != null )
+           
+            for(int i=0;i<this.clauses.size();i++)
             {
-                and.setDB(v);
-            }
-            if ( or != null )
-            {
-                or.setDB(v);
+              ((Criterion)(clauses.elementAt(i))).setDB(v);
             }
         }
 
@@ -3447,48 +3709,45 @@
         /**
          *  get the criterion from this Criterion's AND field.
          */
-        public Criterion getAnd()
+        public Vector getClauses()
+        {
+            return clauses;
+        }
+
+        /**
+         *  get the criterion from this Criterion's AND field.
+         */
+        public Vector getTypes()
         {
-            return and;
+            return types;
         }
 
         /**
-         * Append a Criteria onto this Criteria's AND field.
+         * Append an AND Criterion onto this Criterion's list.
          */
         public Criterion and(Criterion criterion)
         {
-            if (this.and == null)
-            {
-                this.and = criterion;
-            }
-            else
-            {
-                this.and.and(criterion);
-            }
+            this.clauses.addElement(criterion);
+            this.types.addElement(AND);
             return this;
         }
 
         /**
          *  get the criterion from this Criterion's AND field.
          */
+         /*
         public Criterion getOr()
         {
             return or;
-        }
+        }*/
 
         /**
-         * Append a Criterion onto this Criterion's OR field.
+         * Append an OR Criterion onto this Criterion's list.
          */
         public Criterion or(Criterion criterion)
         {
-            if (this.or == null)
-            {
-                this.or = criterion;
-            }
-            else
-            {
-                this.or.or(criterion);
-            }
+            this.clauses.addElement(criterion);
+            this.types.addElement(OR);
             return this;
         }
 
@@ -3500,13 +3759,15 @@
             //
             // it is alright if value == null
             //
-
+           
             if (column == null)
             {
                 return;
             }
 
-            sb.append('(');
+            Criterion x_clause = null;
+            for(int j=0;j<this.clauses.size();j++)
+              sb.append('(');
             if ( CUSTOM == comparison )
             {
                 if ( value != null && ! "".equals(value) )
@@ -3532,18 +3793,13 @@
                                     ignoreStringCase, getDb(), sb);
             }
 
-            if (or != null)
-            {
-                sb.append(OR);
-                or.appendTo(sb);
-            }
-
-            if (and != null)
+            for(int i=0;i<this.clauses.size();i++)
             {
-                sb.append(AND);
-                and.appendTo(sb);
+                sb.append(this.types.elementAt(i));
+                x_clause = (Criterion)(this.clauses.elementAt(i));
+                x_clause.appendTo(sb);
+                sb.append(')');
             }
-            sb.append(')');
         }
 
         /**
@@ -3562,8 +3818,10 @@
             }
 
             DB db = getDb();
-
-            sb.append('(');
+           
+            Criterion x_clause = null;
+            for(int j=0;j<this.clauses.size();j++)
+              sb.append('(');
             if ( CUSTOM == comparison )
             {
                 if ( !"".equals(value) )
@@ -3640,18 +3898,15 @@
                 }
             }
 
-            if (or != null)
+            for(int i=0;i<this.clauses.size();i++)
             {
-                sb.append(OR);
-                or.appendPsTo(sb,params);
+                sb.append(this.types.elementAt(i));
+                x_clause = (Criterion)(this.clauses.elementAt(i));
+                x_clause.appendPsTo(sb,params);
+                sb.append(')');
             }
+           
 
-            if (and != null)
-            {
-                sb.append(AND);
-                and.appendPsTo(sb,params);
-            }
-            sb.append(')');
         }
 
         /**
@@ -3717,12 +3972,14 @@
             }
 
             // check chained criterion
-            isEquiv &= (and == null && crit.getAnd() == null )
-                || (and != null && and.equals(crit.getAnd()));
-
-            isEquiv &= (or == null && crit.getOr() == null )
-                || (or != null && or.equals(crit.getOr()));
-
+           
+            isEquiv &= this.clauses.size() == crit.getClauses().size();
+            for(int i=0;i<this.clauses.size();i++)
+            {
+              isEquiv &=  
((String)(types.elementAt(i))).equals((String)(crit.getTypes().elementAt(i))); 

+              isEquiv &=  
((Criterion)(clauses.elementAt(i))).equals((Criterion)(crit.getClauses().elementAt(i))); 

+            }
+               
             return isEquiv;
         }
 
@@ -3743,19 +4000,17 @@
                 h ^= column.hashCode();
             }
 
-            if (and != null)
+            for(int i=0;i<this.clauses.size();i++)
             {
-                h ^= and.hashCode();
-            }
-
-            if (or != null)
-            {
-                h ^= or.hashCode();
+                h ^= ((Criterion)(clauses.elementAt(i))).hashCode();
             }
 
             return h;
         }
 
+        /**
+         * get all tables from nested criterion objects
+         */
         public String[] getAllTables()
         {
             StringStack tables = new StringStack();
@@ -3763,16 +4018,24 @@
             return tables.toStringArray();
         }
 
+        /**
+         * method supporting recursion through all criterions to give
+         * us a StringStack of tables from each criterion
+         */
         private void addCriterionTable(Criterion c, StringStack s)
         {
             if ( c != null )
             {
                 s.add(c.getTable());
-                addCriterionTable(c.getAnd(), s);
-                addCriterionTable(c.getOr(), s);
+                for(int i=0;i<c.getClauses().size();i++)
+                  
addCriterionTable((Criterion)(c.getClauses().elementAt(i)), s);
             }
         }
-
+       
+        /**
+         * get an array of all criterion attached to this
+         * recursing through all sub criterion
+         */
         public Criterion[] getAttachedCriterion()
         {
             ArrayList crits = new ArrayList();
@@ -3786,14 +4049,19 @@
             return crita;
         }
 
+        /**
+         * method supporting recursion through all criterions to give
+         * us an ArrayList of them
+         */
         private void traverseCriterion(Criterion c, ArrayList a)
         {
             if ( c != null )
             {
                 a.add(c);
-                traverseCriterion(c.getAnd(), a);
-                traverseCriterion(c.getOr(), a);
+                for(int i=0;i<c.getClauses().size();i++)
+                  
traverseCriterion((Criterion)(c.getClauses().elementAt(i)), a);
             }
         }
     }
 }
+



--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>