Right, well it took about 5 hours longer than expected, what with
downloading the new torque source, downloading the new maven, updating
the jars, re-compiling my project, and then editing all the Vector/List
changes, but I now have a set of patches that do a number of things:
1. Add GROUP BY and HAVING functionality to the Criteria class through
addHaving() and addGroupByColumn() methods
2. Adjusts BasePeer so that databases that do not support native limit
syntax, or have weird ones (like MSSQL) will still function with
specified offset and limit parameters
3. Adjusts the MSSQL adapter so that it says it can't support native
limit operations and thus works with 2 above
4. Makes SqlEnum a public class so that people can pass different
comparators into Peer objects.
All the patches contain some chunks that will be rejected, but
everything seems to work. I think the rejects are due to coding style
conflicts in the patch I originally submitted to solve the precedence
problem in Criterion, that were then adjusted when Eric put the patches
into cvs.
Oh yes, and my criterion string parsing classes that are used by the
CriteriaTest are now in a separate file CriterionParser.java - included
for your amusement.
I think the changes are fairly self-explanatory from the code, but
please ask away if there are any questions. All of the above have been
checked on MySQL 3.23.47-nt and SQLServer version 7.0
Now on to the actual work I was going to do today .....
Index: src/java/org/apache/torque/adapter/DBMSSQL.java
===================================================================
RCS file:
/home/cvspublic/jakarta-turbine-torque/src/java/org/apache/torque/adapter/DBMSSQL.java,v
retrieving revision 1.4
diff -u -r1.4 DBMSSQL.java
--- src/java/org/apache/torque/adapter/DBMSSQL.java 12 Apr 2002 05:58:32 -0000
1.4
+++ src/java/org/apache/torque/adapter/DBMSSQL.java 3 May 2002 06:45:42 -0000
@@ -73,4 +73,15 @@
protected DBMSSQL()
{
}
+
+ /**
+ * This method is used to chek whether the database natively
+ * supports limiting the size of the resultset.
+ *
+ * @return True.
+ */
+ public boolean supportsNativeLimit()
+ {
+ return false;
+ }
}
Index: src/java/org/apache/torque/util/SqlEnum.java
===================================================================
RCS file:
/home/cvspublic/jakarta-turbine-torque/src/java/org/apache/torque/util/SqlEnum.java,v
retrieving revision 1.4
diff -u -r1.4 SqlEnum.java
--- src/java/org/apache/torque/util/SqlEnum.java 20 Jan 2002 21:37:56 -0000
1.4
+++ src/java/org/apache/torque/util/SqlEnum.java 3 May 2002 02:06:43 -0000
@@ -64,7 +64,7 @@
* @version $Id: SqlEnum.java,v 1.4 2002/01/20 21:37:56 jon Exp $
* @since 3.0
*/
-class SqlEnum implements java.io.Serializable
+public class SqlEnum implements java.io.Serializable
{
private final String s;
package org.apache.torque.util;
/* ====================================================================
* The Apache Software License, Version 1.1
*
* Copyright (c) 2001-2002 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Apache" and "Apache Software Foundation" and
* "Apache Turbine" must not be used to endorse or promote products
* derived from this software without prior written permission. For
* written permission, please contact [EMAIL PROTECTED]
*
* 5. Products derived from this software may not be called "Apache",
* "Apache Turbine", nor may "Apache" appear in their name, without
* prior written permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
import java.lang.reflect.Array;
import java.math.BigDecimal;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Vector;
import org.apache.torque.Torque;
import org.apache.torque.TorqueException;
import org.apache.torque.adapter.DB;
import org.apache.torque.map.DatabaseMap;
import org.apache.torque.map.TableMap;
import org.apache.torque.om.DateKey;
import org.apache.torque.om.ObjectKey;
import org.apache.torque.util.BasePeer;
import org.apache.commons.collections.StringStack;
import org.apache.log4j.Category;
import org.apache.torque.util.Criteria.Criterion;
import org.apache.torque.util.SqlEnum;
/**
* This is a utility class that can translate string representations
* of criterion clauses back into criterion clauses.
*
* NOTE: other methods will be added as needed and as time permits.
*
* @author <a href="mailto:[EMAIL PROTECTED]">Sam Joseph</a>
* @version $Id: $
*/
public class CriterionParser extends Criteria
{
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;
}
}
--
To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>