EMPIREDB-362 Bugfix: PreparedStatments parameters out of order for Joins with additional constraints
diff --git a/empire-db/src/main/java/org/apache/empire/commons/ObjectUtils.java b/empire-db/src/main/java/org/apache/empire/commons/ObjectUtils.java
index 886741c..68589ab 100644
--- a/empire-db/src/main/java/org/apache/empire/commons/ObjectUtils.java
+++ b/empire-db/src/main/java/org/apache/empire/commons/ObjectUtils.java
@@ -33,6 +33,7 @@
import java.util.Locale;
import org.apache.commons.beanutils.MethodUtils;
+import org.apache.empire.data.ColumnExpr;
import org.apache.empire.exceptions.InvalidArgumentException;
import org.apache.empire.exceptions.InvalidValueException;
import org.apache.empire.exceptions.ItemNotFoundException;
@@ -249,7 +250,7 @@
}
/**
- * Compares two object arrrays for equality
+ * Compares two arrays for equality
*
* @param array1 the first array
* @param array2 the second array
@@ -272,6 +273,24 @@
}
/**
+ * Compares two ColumnExpr for equality
+ *
+ * @param expr1
+ * @param expr2
+ *
+ * @return true if both expressions are equal or false otherwise
+ */
+ public static boolean compareEqual(ColumnExpr expr, ColumnExpr other)
+ {
+ if (other.isWrapper() && !expr.isWrapper())
+ return expr.equals(other.unwrap());
+ else if (!other.isWrapper() && expr.isWrapper())
+ return expr.unwrap().equals(other);
+ // both wrapped or both unwrapped
+ return expr.equals(other);
+ }
+
+ /**
* Checks whether a preferred value is valid and returns an alternative value if not.
* @param <T> the type of the values
* @param preferred the preferred return value
diff --git a/empire-db/src/main/java/org/apache/empire/db/DBCommand.java b/empire-db/src/main/java/org/apache/empire/db/DBCommand.java
index 67f6a7e..6883adb 100644
--- a/empire-db/src/main/java/org/apache/empire/db/DBCommand.java
+++ b/empire-db/src/main/java/org/apache/empire/db/DBCommand.java
@@ -26,10 +26,16 @@
import java.util.List;
import java.util.Set;
+import org.apache.empire.commons.ObjectUtils;
import org.apache.empire.commons.StringUtils;
+import org.apache.empire.commons.Unwrappable;
import org.apache.empire.data.DataType;
+import org.apache.empire.db.expr.column.DBAliasExpr;
+import org.apache.empire.db.expr.column.DBValueExpr;
+import org.apache.empire.db.expr.compare.DBCompareAndOrExpr;
import org.apache.empire.db.expr.compare.DBCompareColExpr;
import org.apache.empire.db.expr.compare.DBCompareExpr;
+import org.apache.empire.db.expr.compare.DBCompareNotExpr;
import org.apache.empire.db.expr.join.DBColumnJoinExpr;
import org.apache.empire.db.expr.join.DBCompareJoinExpr;
import org.apache.empire.db.expr.join.DBCrossJoinExpr;
@@ -37,9 +43,9 @@
import org.apache.empire.db.expr.order.DBOrderByExpr;
import org.apache.empire.db.expr.set.DBSetExpr;
import org.apache.empire.dbms.DBSqlPhrase;
-import org.apache.empire.exceptions.InternalException;
import org.apache.empire.exceptions.InvalidArgumentException;
import org.apache.empire.exceptions.ItemNotFoundException;
+import org.apache.empire.exceptions.NotSupportedException;
import org.apache.empire.exceptions.ObjectNotValidException;
import org.apache.empire.exceptions.UnspecifiedErrorException;
import org.slf4j.Logger;
@@ -56,6 +62,172 @@
{
// *Deprecated* private static final long serialVersionUID = 1L;
+ /**
+ * DBMergeCommand
+ * @author rainer
+ */
+ protected static class DBMergeCommand extends DBCommand
+ {
+ private final DBCommand parent;
+
+ protected DBMergeCommand(DBCommand parent)
+ {
+ super(parent.isAutoPrepareStmt());
+ this.parent = parent;
+ // set
+ List<DBSetExpr> set = parent.getSetExpressions();
+ if (set!=null)
+ this.set = new ArrayList<DBSetExpr>(set);
+ // joins
+ List<DBJoinExpr> joins = parent.getJoins();
+ if (joins!=null)
+ this.joins = new ArrayList<DBJoinExpr>(joins);
+ // where
+ List<DBCompareExpr> where = parent.getWhereConstraints();
+ if (where!=null)
+ this.where = new ArrayList<DBCompareExpr>(where);
+ // groupBy
+ List<DBColumnExpr> groupBy = parent.getGroupBy();
+ if (groupBy!=null)
+ this.groupBy = new ArrayList<DBColumnExpr>(groupBy);
+ // having
+ List<DBCompareExpr> having = parent.getHavingConstraints();
+ if (having!=null)
+ this.having = new ArrayList<DBCompareExpr>(having);
+ }
+
+ @Override
+ protected void notifyParamUsage(DBCmdParam param)
+ {
+ throw new NotSupportedException(this, "notifyParamUsage");
+ }
+
+ @Override
+ protected void resetParamUsage()
+ {
+ /* Nothing */
+ }
+
+ @Override
+ protected void completeParamUsage()
+ {
+ /* Nothing */
+ }
+
+ @Override
+ protected void mergeSubqueryParams(Object[] subQueryParams)
+ {
+ parent.mergeSubqueryParams(subQueryParams);
+ }
+
+ @Override
+ protected void addJoin(StringBuilder buf, DBJoinExpr join, long context, int whichParams)
+ {
+ parent.addJoin(buf, join, context, whichParams);
+ }
+
+ public List<DBSetExpr> addUsing(StringBuilder buf, DBRowSet table, DBColumnJoinExpr updateJoin)
+ {
+ buf.append("\r\nUSING ");
+ // clearSelect();
+ // clearOrderBy();
+ DBRowSet outerTable = updateJoin.getOuterTable();
+ if (outerTable==null)
+ outerTable=table;
+ Set<DBColumn> joinColumns = new HashSet<DBColumn>();
+ updateJoin.addReferencedColumns(joinColumns);
+ for (DBColumn jcol : joinColumns)
+ { // Select join columns
+ if (jcol.getRowSet().equals(outerTable)==false)
+ select(jcol);
+ }
+ // find the source table
+ DBColumnExpr left = updateJoin.getLeft();
+ DBColumnExpr right = updateJoin.getRight();
+ DBRowSet source = right.getUpdateColumn().getRowSet();
+ if (source==table)
+ source = left.getUpdateColumn().getRowSet();
+ // Add set expressions
+ String sourceAliasPrefix = source.getAlias()+".";
+ List<DBSetExpr> mergeSet = new ArrayList<DBSetExpr>(set.size());
+ for (DBSetExpr sex : set)
+ { // Select set expressions
+ Object val = sex.getValue();
+ if (val instanceof DBColumnExpr)
+ {
+ DBColumnExpr expr = ((DBColumnExpr)val);
+ if (!(expr instanceof DBColumn) && !(expr instanceof DBAliasExpr))
+ { // rename column
+ String name = "COL_"+String.valueOf(mergeSet.size());
+ expr = expr.as(name);
+ }
+ // select
+ select(expr);
+ // Name
+ DBValueExpr NAME_EXPR = getDatabase().getValueExpr(sourceAliasPrefix+expr.getName(), DataType.UNKNOWN);
+ mergeSet.add(sex.getColumn().to(NAME_EXPR));
+ }
+ else
+ { // add original
+ mergeSet.add(sex);
+ }
+ }
+ // remove join (if not necessary)
+ if (hasConstraintOn(table)==false)
+ removeJoinsOn(table);
+ // add SQL for inner statement
+ addSQL(buf, CTX_DEFAULT);
+ // add Alias
+ buf.append(" ");
+ buf.append(source.getAlias());
+ buf.append("\r\nON (");
+ left.addSQL(buf, CTX_DEFAULT);
+ buf.append(" = ");
+ right.addSQL(buf, CTX_DEFAULT);
+ // Compare Expression
+ if (updateJoin.getWhere() != null)
+ appendMergeConstraint(buf, table, updateJoin.getWhere());
+ // More constraints
+ for (DBCompareExpr cmpExpr : this.where)
+ {
+ appendMergeConstraint(buf, table, cmpExpr);
+ }
+ // done
+ return mergeSet;
+ }
+
+ protected void appendMergeConstraint(StringBuilder buf, DBRowSet table, DBCompareExpr cmpExpr)
+ {
+ if (cmpExpr instanceof DBCompareColExpr)
+ { // a compare column expression
+ DBCompareColExpr cce = (DBCompareColExpr)cmpExpr;
+ DBColumn ccecol = cce.getColumn().getUpdateColumn();
+ if (table.isKeyColumn(ccecol)&& !isSetColumn(ccecol))
+ { // yes, add
+ buf.append(" AND ");
+ cce.addSQL(buf, CTX_DEFAULT);
+ }
+ }
+ // else if (cmpExpr instanceof DBCompareAndOrExpr)
+ // else if (cmpExpr instanceof DBCompareNotExpr)
+ else
+ { // just add
+ buf.append(" AND ");
+ cmpExpr.addSQL(buf, CTX_DEFAULT);
+ }
+ }
+
+ protected boolean isSetColumn(DBColumn col)
+ {
+ for (DBSetExpr se : this.set)
+ {
+ if (se.getColumn().equals(col))
+ return true;
+ }
+ return false;
+ }
+ }
+
// Logger
protected static final Logger log = LoggerFactory.getLogger(DBCommand.class);
@@ -74,15 +246,6 @@
protected List<DBCmdParam> cmdParams = null;
private int paramUsageCount = 0;
- /**
- * Constructs a new DBCommand object and set the specified DBDatabase object.
- *
- * @param db the current database object
- */
- protected DBCommand(boolean autoPrepareStmt)
- {
- this.autoPrepareStmt = autoPrepareStmt;
- }
/**
* Custom serialization for transient database.
@@ -109,6 +272,78 @@
*/
/**
+ * Constructs a new DBCommand object and set the specified DBDatabase object.
+ *
+ * @param db the current database object
+ */
+ protected DBCommand(boolean autoPrepareStmt)
+ {
+ this.autoPrepareStmt = autoPrepareStmt;
+ }
+
+ /**
+ * @return true if auto Prepared Statements is activated for this record
+ */
+ public final boolean isAutoPrepareStmt()
+ {
+ return autoPrepareStmt;
+ }
+
+ /**
+ * Creates a clone of this class.
+ */
+ @Override
+ public DBCommand clone()
+ {
+ DBCommand clone = (DBCommand)super.clone();
+ // Clone lists
+ if (select!=null)
+ clone.select = new ArrayList<DBColumnExpr>(select);
+ if (set!=null)
+ clone.set = new ArrayList<DBSetExpr>(set);
+ if (joins!=null)
+ clone.joins = new ArrayList<DBJoinExpr>(joins);
+ if (where!=null)
+ clone.where = new ArrayList<DBCompareExpr>(where);
+ if (groupBy!=null)
+ clone.groupBy = new ArrayList<DBColumnExpr>(groupBy);
+ if (having!=null)
+ clone.having = new ArrayList<DBCompareExpr>(having);
+ if (cmdParams!=null && !cmdParams.isEmpty())
+ { // clone params
+ clone.paramUsageCount = 0;
+ clone.cmdParams = new ArrayList<DBCmdParam>(cmdParams.size());
+ // clone set
+ for (int i=0; (clone.set!=null && i<clone.set.size()); i++)
+ clone.set.set(i, clone.set.get(i).copy(clone));
+ // clone where and having
+ for (int i=0; (clone.where!=null && i<clone.where.size()); i++)
+ clone.where.set(i, clone.where.get(i).copy(clone));
+ for (int i=0; (clone.having!=null && i<clone.having.size()); i++)
+ clone.having.set(i, clone.having.get(i).copy(clone));
+ }
+ // done
+ return clone;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public final DBDatabase getDatabase()
+ {
+ if (hasSelectExpr())
+ return this.select.get(0).getDatabase();
+ if (hasSetExpr())
+ return this.set.get(0).getDatabase();
+ // two more chances (should we?)
+ if (where!=null && !where.isEmpty())
+ return where.get(0).getDatabase();
+ if (orderBy!=null && !orderBy.isEmpty())
+ return orderBy.get(0).getDatabase();
+ // not valid yet
+ throw new ObjectNotValidException(this);
+ }
+
+ /**
* internally used to reset the command param usage count.
* Note: Only one thread my generate an SQL statement
*/
@@ -136,7 +371,10 @@
{ // Remove unused parameters
log.warn("DBCommand has {} unused Command params", cmdParams.size()-paramUsageCount);
for (int i=cmdParams.size()-1; i>=paramUsageCount; i--)
- cmdParams.remove(i);
+ { // Remove temporary params
+ if (cmdParams.get(i).getCmd()!=this)
+ cmdParams.remove(i);
+ }
}
}
@@ -146,11 +384,16 @@
protected void notifyParamUsage(DBCmdParam param)
{
int index = cmdParams.indexOf(param);
- if (index < paramUsageCount)
+ if (index<0)
{ // Error: parameter probably used twice in statement!
- throw new UnspecifiedErrorException("A parameter may only be used once in a command.");
+ throw new UnspecifiedErrorException("The CmdParam has not been found on this Command.");
}
- if (index > paramUsageCount)
+ if (index < paramUsageCount)
+ { // Warn: parameter used twice in statement!
+ log.debug("The DBCmdParam already been used. Adding a temporary copy");
+ cmdParams.add(paramUsageCount, new DBCmdParam(null, param.getDataType(), param.getValue()));
+ }
+ else if (index > paramUsageCount)
{ // Correct parameter order
cmdParams.remove(index);
cmdParams.add(paramUsageCount, param);
@@ -161,89 +404,43 @@
/**
* internally used to remove the command param used in a constraint
*/
- private void removeCommandParam(DBCompareColExpr cmp)
+ protected void removeCommandParams(DBCompareExpr cmpExpr)
{
- if (cmdParams!=null && (cmp.getValue() instanceof DBCmdParam))
- cmdParams.remove(cmp.getValue());
+ if (cmdParams==null)
+ return; // Nothing to do
+ // unwrap
+ if (cmpExpr instanceof Unwrappable<?>)
+ cmpExpr = (DBCompareExpr)((Unwrappable<?>)cmpExpr).unwrap();
+ // check type
+ if (cmpExpr instanceof DBCompareColExpr)
+ { // DBCompareColExpr
+ DBCompareColExpr cmp = ((DBCompareColExpr)cmpExpr);
+ if (cmp.getValue() instanceof DBCmdParam)
+ cmdParams.remove(cmp.getValue());
+ }
+ else if (cmpExpr instanceof DBCompareAndOrExpr)
+ { // DBCompareAndOrExpr
+ removeCommandParams(((DBCompareAndOrExpr)cmpExpr).getLeft());
+ removeCommandParams(((DBCompareAndOrExpr)cmpExpr).getRight());
+ }
+ else if (cmpExpr instanceof DBCompareNotExpr)
+ { // DBCompareNotExpr
+ removeCommandParams(((DBCompareNotExpr)cmpExpr).getExpr());
+ }
}
/**
* internally used to remove all command params used in a list of constraints
*/
- private void removeAllCommandParams(List<DBCompareExpr> list)
+ protected void removeAllCommandParams(List<DBCompareExpr> list)
{
if (cmdParams == null)
return;
for(DBCompareExpr cmp : list)
- { // Check whether it is a compare column expr.
- if (!(cmp instanceof DBCompareColExpr))
- continue;
- // Check the value is a DBCommandParam
- removeCommandParam((DBCompareColExpr)cmp);
+ { // Check the value is a DBCommandParam
+ removeCommandParams(cmp);
}
}
-
-
- /**
- * Creates a clone of this class.
- */
- @Override
- public DBCommand clone()
- {
- try
- {
- DBCommand clone = (DBCommand)super.clone();
- // Clone lists
- if (select!=null)
- clone.select = new ArrayList<DBColumnExpr>(select);
- if (set!=null)
- clone.set = new ArrayList<DBSetExpr>(set);
- if (joins!=null)
- clone.joins = new ArrayList<DBJoinExpr>(joins);
- if (where!=null)
- clone.where = new ArrayList<DBCompareExpr>(where);
- if (groupBy!=null)
- clone.groupBy = new ArrayList<DBColumnExpr>(groupBy);
- if (having!=null)
- clone.having = new ArrayList<DBCompareExpr>(having);
- if (cmdParams!=null && !cmdParams.isEmpty())
- { // clone params
- clone.paramUsageCount = 0;
- clone.cmdParams = new ArrayList<DBCmdParam>(cmdParams.size());
- // clone set
- for (int i=0; (clone.set!=null && i<clone.set.size()); i++)
- clone.set.set(i, clone.set.get(i).copy(clone));
- // clone where and having
- for (int i=0; (clone.where!=null && i<clone.where.size()); i++)
- clone.where.set(i, clone.where.get(i).copy(clone));
- for (int i=0; (clone.having!=null && i<clone.having.size()); i++)
- clone.having.set(i, clone.having.get(i).copy(clone));
- }
- // done
- return clone;
-
- } catch (CloneNotSupportedException e) {
- log.error("Cloning DBCommand object failed!", e);
- throw new InternalException(e);
- }
- }
-
- @SuppressWarnings("unchecked")
- @Override
- public final DBDatabase getDatabase()
- {
- if (hasSelectExpr())
- return this.select.get(0).getDatabase();
- if (hasSetExpr())
- return this.set.get(0).getDatabase();
- // two more chances (should we?)
- if (where!=null && !where.isEmpty())
- return where.get(0).getDatabase();
- if (orderBy!=null && !orderBy.isEmpty())
- return orderBy.get(0).getDatabase();
- // not valid yet
- throw new ObjectNotValidException(this);
- }
/**
* Returns true if the this command has either Select or Set expressions
@@ -538,12 +735,11 @@
{
if (set==null)
return false;
- Iterator<DBSetExpr> i = set.iterator();
- while (i.hasNext())
- {
- DBSetExpr chk = i.next();
- if (chk.column.equals(column))
+ for (DBSetExpr setExpr : set)
+ { // Find column
+ if (setExpr.column.equals(column))
return true;
+
}
return false;
}
@@ -992,6 +1188,17 @@
* removes a constraint on a particular column from the where clause
* @param col the column expression for which to remove the constraint
*/
+ public void removeWhereConstraint(DBCompareExpr cmpExpr)
+ {
+ if (where == null)
+ return;
+ removeConstraint(where, cmpExpr);
+ }
+
+ /**
+ * removes a constraint on a particular column from the where clause
+ * @param col the column expression for which to remove the constraint
+ */
public void removeWhereConstraintOn(DBColumnExpr col)
{
if (where == null)
@@ -1056,6 +1263,17 @@
}
/**
+ * removes a constraint on a particular column from the where clause
+ * @param col the column expression for which to remove the constraint
+ */
+ public void removeHavingConstraint(DBCompareExpr cmpExpr)
+ {
+ if (having == null)
+ return;
+ removeConstraint(having, cmpExpr);
+ }
+
+ /**
* removes a constraint on a particular column from the having clause
* @param col the column expression for which to remove the constraint
*/
@@ -1247,6 +1465,16 @@
clearLimit();
resetParamUsage();
}
+
+ /**
+ * Create a special Merge-command
+ * This forwards parameter usage to the parent command
+ * @return the merge command
+ */
+ protected DBMergeCommand createMergeCommand()
+ {
+ return new DBMergeCommand(this);
+ }
/**
* returns true if prepared statements are enabled for this command
@@ -1291,8 +1519,7 @@
if (expr.isMutuallyExclusive(other)==false)
continue;
// Check if we replace a DBCommandParam
- if (other instanceof DBCompareColExpr)
- removeCommandParam((DBCompareColExpr)other);
+ removeCommandParams(other);
// columns match
list.set(i, expr);
return;
@@ -1306,23 +1533,51 @@
* @param list the 'where' or 'having' list
* @param col the column expression for which to remove the constraint
*/
- protected void removeConstraintOn(List<DBCompareExpr> list, DBColumnExpr col)
+ protected void removeConstraint(List<DBCompareExpr> list, DBCompareExpr cmpExpr)
+ {
+ if (list == null)
+ return;
+ for (DBCompareExpr cmp : list)
+ { // Compare columns
+ if (cmp.isMutuallyExclusive(cmpExpr))
+ { // Check if we replace a DBCommandParam
+ removeCommandParams(cmp);
+ // remove the constraint
+ list.remove(cmp);
+ return;
+ }
+ }
+ }
+
+ /**
+ * removes a constraint on a particular column to the 'where' or 'having' collections
+ * @param list the 'where' or 'having' list
+ * @param col the column expression for which to remove the constraint
+ */
+ protected void removeConstraintOn(List<DBCompareExpr> list, DBColumnExpr colExpr)
{
if (list == null)
return;
- for(DBCompareExpr cmp : list)
+ for (DBCompareExpr cmp : list)
{ // Check whether it is a compare column expr.
if (!(cmp instanceof DBCompareColExpr))
continue;
// Compare columns
- DBColumnExpr c = ((DBCompareColExpr)cmp).getColumn();
- DBColumn udc = c.getUpdateColumn();
- if (c.equals(col) || (udc!=null && udc.equals(col.getUpdateColumn())))
+ DBColumnExpr cmpCol = ((DBCompareColExpr)cmp).getColumn();
+ if (ObjectUtils.compareEqual(cmpCol, colExpr))
{ // Check if we replace a DBCommandParam
- removeCommandParam((DBCompareColExpr)cmp);
- // remove the constraint
- list.remove(cmp);
- return;
+ removeCommandParams(cmp);
+ // remove the constraint
+ list.remove(cmp);
+ return;
+ }
+ // Update column
+ if ((colExpr instanceof DBColumn) && !(cmpCol instanceof DBColumn) && colExpr.equals(colExpr.getUpdateColumn()))
+ { // Check if we replace a DBCommandParam
+ removeCommandParams(cmp);
+ // remove the constraint
+ list.remove(cmp);
+ return;
}
}
}
@@ -1381,20 +1636,20 @@
/**
* Returns an array of parameter values for a prepared statement.
- * To ensure that all values are in the order of their occurrence, getSelect() should be called first.
+ * The parameters are supplied only after getSelect(), getUpdate(), getInsert() or getDelete() have been called
* @return an array of parameter values for a prepared statement
*/
@Override
public Object[] getParamValues()
{
- if (cmdParams==null || cmdParams.size()==0)
+ if (cmdParams==null || paramUsageCount==0)
return null;
// Check whether all parameters have been used
- if (paramUsageCount>0 && paramUsageCount!=cmdParams.size())
- log.warn("DBCommand parameter count ("+String.valueOf(cmdParams.size())
- + ") does not match parameter use count ("+String.valueOf(paramUsageCount)+")");
+ if (paramUsageCount!=cmdParams.size())
+ log.info("DBCommand parameter count ("+String.valueOf(cmdParams.size())
+ + ") does not match parameter use count ("+String.valueOf(paramUsageCount)+")");
// Create result array
- Object[] values = new Object[cmdParams.size()];
+ Object[] values = new Object[paramUsageCount];
for (int i=0; i<values.length; i++)
values[i]=cmdParams.get(i).getValue();
// values
@@ -1449,11 +1704,8 @@
{ // Convert ColumnExpression List to Column List
compexpr = new ArrayList<DBCompareColExpr>(where.size());
for (DBCompareExpr expr : where)
- { if (expr instanceof DBCompareColExpr)
- { DBColumn column = ((DBCompareColExpr)expr).getColumn().getUpdateColumn();
- if (column!=null && hasSetExprOn(column)==false)
- compexpr.add((DBCompareColExpr)expr);
- }
+ {
+ appendCompareColExprs(table, expr, compexpr);
}
// Add Column Names from where clause
if (compexpr.size()>0)
@@ -1485,6 +1737,29 @@
completeParamUsage();
return buf.toString();
}
+
+ protected void appendCompareColExprs(DBRowSet table, DBCompareExpr expr, List<DBCompareColExpr> list)
+ {
+ // unwrap
+ if (expr instanceof Unwrappable<?>)
+ expr = (DBCompareExpr)((Unwrappable<?>)expr).unwrap();
+ // check type
+ if (expr instanceof DBCompareColExpr)
+ { // DBCompareColExpr
+ DBColumn column = ((DBCompareColExpr)expr).getColumn().getUpdateColumn();
+ if (column!=null && column.getRowSet().equals(table) && !hasSetExprOn(column))
+ list.add((DBCompareColExpr)expr);
+ }
+ else if (expr instanceof DBCompareAndOrExpr)
+ { // DBCompareAndOrExpr
+ appendCompareColExprs(table, ((DBCompareAndOrExpr)expr).getLeft(), list);
+ appendCompareColExprs(table, ((DBCompareAndOrExpr)expr).getRight(), list);
+ }
+ else if (expr instanceof DBCompareNotExpr)
+ { // DBCompareNotExpr
+ appendCompareColExprs(table, ((DBCompareNotExpr)expr).getExpr(), list);
+ }
+ }
/**
* Creates an update SQL-Statement
@@ -1627,11 +1902,8 @@
buf.append( "\t" );
whichParams = 1;
}
- join.addSQL(buf, context);
- // Merge subquery params
- Object[] subQueryParams = join.getSubqueryParams(whichParams);
- if (subQueryParams!=null)
- mergeSubqueryParams(subQueryParams);
+ // check
+ addJoin(buf, join, context, whichParams);
// add CRLF
if( i!=joins.size()-1 )
buf.append("\r\n");
@@ -1664,6 +1936,29 @@
}
}
+ protected void addJoin(StringBuilder buf, DBJoinExpr join, long context, int whichParams)
+ {
+ // remember insert pos
+ int paramInsertPos = paramUsageCount;
+ // now add the join
+ join.addSQL(buf, context);
+ // Merge subquery params
+ Object[] subQueryParams = join.getSubqueryParams(whichParams);
+ if (subQueryParams!=null)
+ {
+ if (paramInsertPos == paramUsageCount)
+ mergeSubqueryParams(subQueryParams);
+ else
+ { // Some Params have been used in additional Join constraints
+ int tempCounter = paramUsageCount;
+ paramUsageCount = paramInsertPos;
+ mergeSubqueryParams(subQueryParams);
+ int insertCount = (paramUsageCount - paramInsertPos);
+ paramUsageCount = tempCounter + insertCount;
+ }
+ }
+ }
+
protected void mergeSubqueryParams(Object[] subQueryParams)
{
if (subQueryParams==null || subQueryParams.length==0)
diff --git a/empire-db/src/main/java/org/apache/empire/db/DBCommandExpr.java b/empire-db/src/main/java/org/apache/empire/db/DBCommandExpr.java
index 2db0887..24fac9a 100644
--- a/empire-db/src/main/java/org/apache/empire/db/DBCommandExpr.java
+++ b/empire-db/src/main/java/org/apache/empire/db/DBCommandExpr.java
@@ -26,8 +26,11 @@
import org.apache.empire.commons.Options;
import org.apache.empire.data.DataType;
import org.apache.empire.db.expr.compare.DBCompareExpr;
+import org.apache.empire.db.expr.join.DBJoinExpr;
import org.apache.empire.db.expr.order.DBOrderByExpr;
+import org.apache.empire.db.expr.set.DBSetExpr;
import org.apache.empire.dbms.DBMSHandler;
+import org.apache.empire.exceptions.InternalException;
import org.apache.empire.exceptions.InvalidArgumentException;
import org.apache.empire.exceptions.NotSupportedException;
import org.apache.empire.exceptions.ObjectNotValidException;
@@ -290,6 +293,25 @@
// Default Constructor
}
+ /**
+ * Creates a clone of this class.
+ */
+ @Override
+ public DBCommandExpr clone()
+ {
+ try
+ { DBCommandExpr clone = (DBCommandExpr)super.clone();
+ // Clone lists
+ if (orderBy!=null)
+ clone.orderBy = new ArrayList<DBOrderByExpr>(orderBy);
+ // done
+ return clone;
+ } catch (CloneNotSupportedException e) {
+ log.error("Cloning DBCommand object failed!", e);
+ throw new InternalException(e);
+ }
+ }
+
public abstract boolean isValid();
/**
diff --git a/empire-db/src/main/java/org/apache/empire/db/DBQuery.java b/empire-db/src/main/java/org/apache/empire/db/DBQuery.java
index ca4981c..553ff8e 100644
--- a/empire-db/src/main/java/org/apache/empire/db/DBQuery.java
+++ b/empire-db/src/main/java/org/apache/empire/db/DBQuery.java
@@ -246,7 +246,7 @@
{
for (int i = 0; i < queryColumns.length; i++)
{
- if (queryColumns[i].exprEquals(expr))
+ if (ObjectUtils.compareEqual(queryColumns[i].getExpr(), expr))
return queryColumns[i];
}
// not found
diff --git a/empire-db/src/main/java/org/apache/empire/db/DBQueryColumn.java b/empire-db/src/main/java/org/apache/empire/db/DBQueryColumn.java
index 2f568a3..43d4772 100644
--- a/empire-db/src/main/java/org/apache/empire/db/DBQueryColumn.java
+++ b/empire-db/src/main/java/org/apache/empire/db/DBQueryColumn.java
@@ -46,16 +46,6 @@
{
return expr;
}
-
- public boolean exprEquals(DBColumnExpr other)
- {
- if (other.isWrapper() && !expr.isWrapper())
- return expr.equals(other.unwrap());
- else if (!other.isWrapper() && expr.isWrapper())
- return expr.unwrap().equals(other);
- // both wrapped or both unwrapped
- return expr.equals(other);
- }
@Override
public DataType getDataType()
diff --git a/empire-db/src/main/java/org/apache/empire/dbms/hsql/DBCommandHSql.java b/empire-db/src/main/java/org/apache/empire/dbms/hsql/DBCommandHSql.java
index bc88c43..d9a3c39 100644
--- a/empire-db/src/main/java/org/apache/empire/dbms/hsql/DBCommandHSql.java
+++ b/empire-db/src/main/java/org/apache/empire/dbms/hsql/DBCommandHSql.java
@@ -24,6 +24,7 @@
import java.util.Set;
import org.apache.empire.data.DataType;
+import org.apache.empire.db.DBCmdParam;
import org.apache.empire.db.DBColumn;
import org.apache.empire.db.DBColumnExpr;
import org.apache.empire.db.DBCommand;
@@ -116,101 +117,12 @@
}
if (updateJoin==null)
throw new ObjectNotValidException(this);
- Set<DBColumn> joinColumns = new HashSet<DBColumn>();
- updateJoin.addReferencedColumns(joinColumns);
// using
- buf.append("\r\nUSING ");
- DBCommand inner = this.clone();
- inner.clearSelect();
- inner.clearOrderBy();
- DBRowSet outerTable = updateJoin.getOuterTable();
- if (outerTable==null)
- outerTable=table;
- for (DBColumn jcol : joinColumns)
- { // Select join columns
- if (jcol.getRowSet().equals(outerTable)==false)
- inner.select(jcol);
- }
- // find the source table
- DBColumnExpr left = updateJoin.getLeft();
- DBColumnExpr right = updateJoin.getRight();
- DBRowSet source = right.getUpdateColumn().getRowSet();
- if (source==table)
- source = left.getUpdateColumn().getRowSet();
- // Add set expressions
- String sourceAliasPrefix = source.getAlias()+".";
- List<DBSetExpr> mergeSet = new ArrayList<DBSetExpr>(set.size());
- for (DBSetExpr sex : set)
- { // Select set expressions
- Object val = sex.getValue();
- if (val instanceof DBColumnExpr)
- {
- DBColumnExpr expr = ((DBColumnExpr)val);
- if (!(expr instanceof DBColumn) && !(expr instanceof DBAliasExpr))
- { // rename column
- String name = "COL_"+String.valueOf(mergeSet.size());
- expr = expr.as(name);
- }
- // select
- inner.select(expr);
- // Name
- DBValueExpr NAME_EXPR = getDatabase().getValueExpr(sourceAliasPrefix+expr.getName(), DataType.UNKNOWN);
- mergeSet.add(sex.getColumn().to(NAME_EXPR));
- }
- else
- { // add original
- mergeSet.add(sex);
- }
- }
- // remove join (if not necessary)
- if (inner.hasConstraintOn(table)==false)
- inner.removeJoinsOn(table);
- // add SQL for inner statement
- inner.addSQL(buf, CTX_DEFAULT);
- // add Alias
- buf.append(" ");
- buf.append(source.getAlias());
- buf.append("\r\nON (");
- left.addSQL(buf, CTX_DEFAULT);
- buf.append(" = ");
- right.addSQL(buf, CTX_DEFAULT);
- // Compare Expression
- if (updateJoin.getWhere() != null)
- { buf.append(" AND ");
- updateJoin.getWhere().addSQL(buf, CTX_DEFAULT);
- }
- // More constraints
- for (DBCompareExpr we : this.where)
- {
- if (we instanceof DBCompareColExpr)
- { // a compare column expression
- DBCompareColExpr cce = (DBCompareColExpr)we;
- DBColumn ccecol = cce.getColumn().getUpdateColumn();
- if (table.isKeyColumn(ccecol)&& !isSetColumn(ccecol))
- {
- buf.append(" AND ");
- cce.addSQL(buf, CTX_DEFAULT);
- }
- }
- else
- { // just add
- buf.append(" AND ");
- we.addSQL(buf, CTX_DEFAULT);
- }
- }
+ DBMergeCommand merge = createMergeCommand();
+ List<DBSetExpr> mergeSet = merge.addUsing(buf, table, updateJoin);
// Set Expressions
buf.append(")\r\nWHEN MATCHED THEN UPDATE ");
buf.append("\r\nSET ");
addListExpr(buf, mergeSet, CTX_DEFAULT, ", ");
}
-
- protected boolean isSetColumn(DBColumn col)
- {
- for (DBSetExpr se : this.set)
- {
- if (se.getColumn().equals(col))
- return true;
- }
- return false;
- }
}
diff --git a/empire-db/src/main/java/org/apache/empire/dbms/oracle/DBCommandOracle.java b/empire-db/src/main/java/org/apache/empire/dbms/oracle/DBCommandOracle.java
index 506f1f3..3791a1b 100644
--- a/empire-db/src/main/java/org/apache/empire/dbms/oracle/DBCommandOracle.java
+++ b/empire-db/src/main/java/org/apache/empire/dbms/oracle/DBCommandOracle.java
@@ -18,22 +18,12 @@
*/
package org.apache.empire.dbms.oracle;
-import java.util.ArrayList;
-// Imports
-import java.util.HashSet;
import java.util.List;
-import java.util.Set;
import org.apache.empire.commons.StringUtils;
-import org.apache.empire.data.DataType;
-import org.apache.empire.db.DBColumn;
-import org.apache.empire.db.DBColumnExpr;
import org.apache.empire.db.DBCommand;
import org.apache.empire.db.DBIndex;
import org.apache.empire.db.DBRowSet;
-import org.apache.empire.db.expr.column.DBAliasExpr;
-import org.apache.empire.db.expr.column.DBValueExpr;
-import org.apache.empire.db.expr.compare.DBCompareColExpr;
import org.apache.empire.db.expr.compare.DBCompareExpr;
import org.apache.empire.db.expr.join.DBColumnJoinExpr;
import org.apache.empire.db.expr.join.DBJoinExpr;
@@ -287,103 +277,14 @@
}
if (updateJoin==null)
throw new ObjectNotValidException(this);
- Set<DBColumn> joinColumns = new HashSet<DBColumn>();
- updateJoin.addReferencedColumns(joinColumns);
// using
- buf.append("\r\nUSING ");
- DBCommand inner = this.clone();
- inner.clearSelect();
- inner.clearOrderBy();
- DBRowSet outerTable = updateJoin.getOuterTable();
- if (outerTable==null)
- outerTable=table;
- for (DBColumn jcol : joinColumns)
- { // Select join columns
- if (jcol.getRowSet().equals(outerTable)==false)
- inner.select(jcol);
- }
- // find the source table
- DBColumnExpr left = updateJoin.getLeft();
- DBColumnExpr right = updateJoin.getRight();
- DBRowSet source = right.getUpdateColumn().getRowSet();
- if (source==table)
- source = left.getUpdateColumn().getRowSet();
- // Add set expressions
- String sourceAliasPrefix = source.getAlias()+".";
- List<DBSetExpr> mergeSet = new ArrayList<DBSetExpr>(set.size());
- for (DBSetExpr sex : set)
- { // Select set expressions
- Object val = sex.getValue();
- if (val instanceof DBColumnExpr)
- {
- DBColumnExpr expr = ((DBColumnExpr)val);
- if (!(expr instanceof DBColumn) && !(expr instanceof DBAliasExpr))
- { // rename column
- String name = "COL_"+String.valueOf(mergeSet.size());
- expr = expr.as(name);
- }
- // select
- inner.select(expr);
- // Name
- DBValueExpr NAME_EXPR = getDatabase().getValueExpr(sourceAliasPrefix+expr.getName(), DataType.UNKNOWN);
- mergeSet.add(sex.getColumn().to(NAME_EXPR));
- }
- else
- { // add original
- mergeSet.add(sex);
- }
- }
- // remove join (if not necessary)
- if (inner.hasConstraintOn(table)==false)
- inner.removeJoinsOn(table);
- // add SQL for inner statement
- inner.addSQL(buf, CTX_DEFAULT);
- // add Alias
- buf.append(" ");
- buf.append(source.getAlias());
- buf.append("\r\nON (");
- left.addSQL(buf, CTX_DEFAULT);
- buf.append(" = ");
- right.addSQL(buf, CTX_DEFAULT);
- // Compare Expression
- if (updateJoin.getWhere() != null)
- { buf.append(" AND ");
- updateJoin.getWhere().addSQL(buf, CTX_DEFAULT);
- }
- // More constraints
- for (DBCompareExpr we : this.where)
- {
- if (we instanceof DBCompareColExpr)
- { // a compare column expression
- DBCompareColExpr cce = (DBCompareColExpr)we;
- DBColumn ccecol = cce.getColumn().getUpdateColumn();
- if (table.isKeyColumn(ccecol)&& !isSetColumn(ccecol))
- {
- buf.append(" AND ");
- cce.addSQL(buf, CTX_DEFAULT);
- }
- }
- else
- { // just add
- buf.append(" AND ");
- we.addSQL(buf, CTX_DEFAULT);
- }
- }
+ DBMergeCommand merge = createMergeCommand();
+ List<DBSetExpr> mergeSet = merge.addUsing(buf, table, updateJoin);
// Set Expressions
buf.append(")\r\nWHEN MATCHED THEN UPDATE ");
buf.append("\r\nSET ");
addListExpr(buf, mergeSet, CTX_DEFAULT, ", ");
}
-
- protected boolean isSetColumn(DBColumn col)
- {
- for (DBSetExpr se : this.set)
- {
- if (se.getColumn().equals(col))
- return true;
- }
- return false;
- }
/**
* Creates an Oracle specific delete statement.
diff --git a/empire-db/src/test/java/org/apache/empire/commons/ObjectUtilsTest.java b/empire-db/src/test/java/org/apache/empire/commons/ObjectUtilsTest.java
index 72025bf..9b48375 100644
--- a/empire-db/src/test/java/org/apache/empire/commons/ObjectUtilsTest.java
+++ b/empire-db/src/test/java/org/apache/empire/commons/ObjectUtilsTest.java
@@ -60,7 +60,7 @@
@Test
public void testCompareEqual()
{
- assertTrue(ObjectUtils.compareEqual(null, null));
+ assertTrue(ObjectUtils.compareEqual((Object)null, null));
Object object = new Object();
assertTrue(ObjectUtils.compareEqual(object, object));