| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| package org.apache.empire.db; |
| |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Set; |
| |
| import org.apache.empire.commons.ObjectUtils; |
| import org.apache.empire.commons.StringUtils; |
| import org.apache.empire.data.DataType; |
| import org.apache.empire.db.expr.column.DBAliasExpr; |
| 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; |
| 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.DBSqlPhrase; |
| import org.apache.empire.exceptions.InvalidArgumentException; |
| import org.apache.empire.exceptions.ItemNotFoundException; |
| import org.apache.empire.exceptions.ObjectNotValidException; |
| import org.apache.empire.exceptions.UnspecifiedErrorException; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| |
| /** |
| * This abstract class handles the creation of the SQL-Commands. |
| * There are methods to create SQL-Commands, like update, insert, |
| * delete and select. |
| */ |
| public abstract class DBCommand extends DBCommandExpr |
| implements Cloneable |
| { |
| // *Deprecated* private static final long serialVersionUID = 1L; |
| |
| // Logger |
| protected static final Logger log = LoggerFactory.getLogger(DBCommand.class); |
| |
| // Distinct Select |
| protected boolean selectDistinct = false; |
| // Lists |
| protected List<DBColumnExpr> select = null; |
| protected List<DBSetExpr> set = null; |
| protected List<DBJoinExpr> joins = null; |
| protected List<DBCompareExpr> where = null; |
| protected List<DBCompareExpr> having = null; |
| protected List<DBColumnExpr> groupBy = null; |
| |
| // Parameters for prepared Statements generation |
| protected boolean autoPrepareStmt = false; |
| protected List<DBCmdParam> cmdParams = null; |
| private int paramUsageCount = 0; |
| |
| |
| /** |
| * Custom serialization for transient database. |
| * |
| private void writeObject(ObjectOutputStream strm) throws IOException |
| { // Database |
| strm.writeObject(db.getIdentifier()); |
| // write the rest |
| strm.defaultWriteObject(); |
| } |
| |
| private void readObject(ObjectInputStream strm) throws IOException, ClassNotFoundException |
| { |
| String dbid = String.valueOf(strm.readObject()); |
| // find database |
| DBDatabase dbo = DBDatabase.findByIdentifier(dbid); |
| if (dbo==null) |
| throw new ItemNotFoundException(dbid); |
| // set final field |
| ClassUtils.setPrivateFieldValue(DBCommand.class, this, "db", dbo); |
| // read the rest |
| strm.defaultReadObject(); |
| } |
| */ |
| |
| /** |
| * 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 joins |
| for (int i=0; (clone.joins!=null && i<clone.joins.size()); i++) |
| clone.joins.set(i, clone.joins.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 |
| */ |
| protected void resetParamUsage() |
| { |
| paramUsageCount = 0; |
| if (cmdParams==null) |
| return; |
| // clear subquery params |
| for (int i=cmdParams.size()-1; i>=0 ;i--) |
| if (cmdParams.get(i).getCmd()!=this) |
| cmdParams.remove(i); |
| } |
| |
| /** |
| * internally used to remove unused Command Params from list |
| * Note: Only one thread my generate an SQL statement |
| */ |
| protected void completeParamUsage() |
| { |
| if (cmdParams==null) |
| return; |
| // check whether all params have been used |
| if (paramUsageCount < cmdParams.size()) |
| { // Remove unused parameters |
| log.warn("DBCommand has {} unused Command params", cmdParams.size()-paramUsageCount); |
| for (int i=cmdParams.size()-1; i>=paramUsageCount; i--) |
| { // Remove temporary params |
| if (cmdParams.get(i).getCmd()!=this) |
| cmdParams.remove(i); |
| } |
| } |
| } |
| |
| /** |
| * internally used to reorder the command params to match their order of occurance |
| */ |
| protected void notifyParamUsage(DBCmdParam param) |
| { |
| int index = cmdParams.indexOf(param); |
| if (index<0) |
| { // Error: parameter probably used twice in statement! |
| throw new UnspecifiedErrorException("The CmdParam has not been found on this Command."); |
| } |
| 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); |
| } |
| paramUsageCount++; |
| } |
| |
| /** |
| * internally used to remove the command param used in a constraint |
| */ |
| protected void removeCommandParams(DBCompareExpr cmpExpr) |
| { |
| if (cmdParams==null) |
| return; // Nothing to do |
| // 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()); |
| } |
| else if (ObjectUtils.isWrapper(cmpExpr)) |
| { // unwrap |
| removeCommandParams(ObjectUtils.unwrap(cmpExpr)); |
| } |
| } |
| |
| /** |
| * internally used to remove all command params used in a list of constraints |
| */ |
| protected void removeAllCommandParams(List<DBCompareExpr> list) |
| { |
| if (cmdParams == null) |
| return; |
| for(DBCompareExpr cmp : list) |
| { // Check the value is a DBCommandParam |
| removeCommandParams(cmp); |
| } |
| } |
| |
| /** |
| * Returns true if the this command has either Select or Set expressions |
| */ |
| @Override |
| public boolean isValid() |
| { |
| return hasSelectExpr() || hasSetExpr(); |
| } |
| |
| /** |
| * Sets whether or not the select statement should contain |
| * the distinct directive . |
| * @return itself (this) |
| */ |
| public DBCommand selectDistinct() |
| { |
| this.selectDistinct = true; |
| return this; |
| } |
| |
| /** |
| * Returns whether or not the select statement will be distinct or not. |
| * |
| * @return true if the select will contain the distinct directive or false otherwise. |
| */ |
| public boolean isSelectDistinct() |
| { |
| return selectDistinct; |
| } |
| |
| /** |
| * returns whether or not the command has any select expression |
| * @return true if the command has any select expression of false otherwise |
| */ |
| @Override |
| public boolean hasSelectExpr() |
| { |
| return (select!=null && !select.isEmpty()); |
| } |
| |
| /** |
| * returns whether or not the command has a specific select expression |
| * @return true if the command contains the given select expression of false otherwise |
| */ |
| @Override |
| public boolean hasSelectExpr(DBColumnExpr expr) |
| { |
| return (select!=null ? (select.indexOf(expr)>=0) : false); |
| } |
| |
| /** |
| * @return the DataType of the selected expression or DataType.UNKNOWN |
| */ |
| @Override |
| public DataType getDataType() |
| { |
| if (select==null || select.size()!=1) |
| return DataType.UNKNOWN; |
| return select.get(0).getDataType(); |
| } |
| |
| /** |
| * Adds a DBColumnExpr object to the Select collection |
| * |
| * @param expr the DBColumnExpr object |
| * @return itself (this) |
| */ |
| public DBCommand select(DBColumnExpr expr) |
| { // Select this column |
| if (select == null) |
| select = new ArrayList<DBColumnExpr>(); |
| if (expr != null && select.contains(expr) == false) |
| select.add(expr); |
| return this; |
| } |
| |
| /** |
| * Adds a list of columns to the select phrase of an sql statement. |
| * |
| * @param exprs an vararg of DBColumnExpr's to select |
| * @return itself (this) |
| */ |
| public final DBCommand select(DBColumnExpr... exprs) |
| { |
| for (DBColumnExpr expr : exprs) |
| { |
| select(expr); |
| } |
| return this; |
| } |
| |
| /** |
| * Adds a collection of columns to the select phrase of an sql statement. |
| * |
| * @param columns the column expressions to add |
| * @return itself (this) |
| */ |
| public final DBCommand select(Collection<? extends DBColumnExpr> columns) |
| { |
| for (DBColumnExpr expr : columns) |
| { |
| select(expr); |
| } |
| return this; |
| } |
| |
| /** |
| * Adds a list of columns with their qualified name to the select phrase of an sql statement. |
| * |
| * @param exprs one or more columns to select |
| * @return itself (this) |
| */ |
| public DBCommand selectQualified(DBColumnExpr... columns) |
| { |
| for (DBColumnExpr col : columns) |
| { |
| select(col.qualified()); |
| } |
| return this; |
| } |
| |
| /** |
| * Adds a collection of columns to the select phrase of an sql statement. |
| * |
| * @param columns the column expressions to add |
| * @return itself (this) |
| */ |
| public final DBCommand selectQualified(Collection<? extends DBColumnExpr> columns) |
| { |
| for (DBColumnExpr col : columns) |
| { |
| select(col.qualified()); |
| } |
| return this; |
| } |
| |
| /** |
| * Makes sure all selected columns are identified by their proper names (qualified) |
| * @return itself (this) |
| */ |
| public DBCommand qualifyAll() |
| { |
| if (select == null) |
| return this; |
| // check select expression |
| for (int i=0; i<select.size(); i++) |
| { |
| DBColumnExpr expr = select.get(i); |
| if (expr instanceof DBColumn) |
| continue; // No need to qualify |
| if (expr instanceof DBAliasExpr) |
| continue; // Already qualified |
| // qualify now |
| select.set(i, expr.qualified()); |
| } |
| return this; |
| } |
| |
| /** |
| * Returns an array of all select expressions |
| * |
| * @return an array of all DBColumnExpr objects or <code>null</code> if there is nothing to select |
| */ |
| @Override |
| public DBColumnExpr[] getSelectExprList() |
| { |
| int count = (select != null) ? select.size() : 0; |
| if (count < 1) |
| return null; |
| // The List |
| DBColumnExpr[] exprList = new DBColumnExpr[count]; |
| for (int i = 0; i < count; i++) |
| exprList[i] = select.get(i); |
| // The expression List |
| return exprList; |
| } |
| |
| /** |
| * Returns all select expressions as unmodifiable list |
| * @return the list of DBColumnExpr used for select |
| */ |
| @Override |
| public List<DBColumnExpr> getSelectExpressions() |
| { |
| return (this.select!=null ? Collections.unmodifiableList(this.select) : null); |
| } |
| |
| /** |
| * replaces a select expression with another or removes a select expression |
| * In order to remove the expression, set the replWith parameter to null |
| * If the replace expression is not found, an ItemNotFoundException is thrown |
| * @param replExpr |
| * @param replWith |
| */ |
| public void replaceSelect(DBColumnExpr replExpr, DBColumnExpr replWith) |
| { |
| int idx = (select != null ? select.indexOf(replExpr) : -1); |
| if (idx < 0) |
| throw new ItemNotFoundException(replExpr); |
| // replace now |
| if (replWith!=null) |
| select.set(idx, replWith); |
| else |
| select.remove(idx); |
| } |
| |
| /** |
| * removes one or more expressions from the Select expression list |
| * @param exprs the expression(s) to be removed |
| */ |
| public void removeSelect(DBColumnExpr... exprs) |
| { |
| if (select==null) |
| return; |
| for (int i=0; i<exprs.length; i++) |
| { |
| int idx = select.indexOf(exprs[i]); |
| if (idx>=0) |
| select.remove(idx); |
| } |
| } |
| |
| /** |
| * Checks whether or not there are any aggregate functions in the Select |
| * @return true if at least on of the selected expressions is an aggregate |
| */ |
| public boolean hasAggegation() |
| { |
| for (DBColumnExpr expr : this.select) |
| { |
| if (expr.isAggregate()) |
| return true; |
| } |
| return false; |
| } |
| |
| /** |
| * Adds a single set expressions to this command |
| * Use column.to(...) to create a set expression |
| * |
| * @param expr the DBSetExpr object(s) |
| * @return itself (this) |
| */ |
| public DBCommand set(DBSetExpr expr) |
| { |
| // add to list |
| if (set == null) |
| set = new ArrayList<DBSetExpr>(); |
| for (int i = 0; i < set.size(); i++) |
| { |
| DBSetExpr chk = set.get(i); |
| if (chk.column.equals(expr.column)) |
| { // Overwrite existing value |
| if (useCmdParam(expr.column, expr.value)) |
| { // Use parameter value |
| if (chk.value instanceof DBCmdParam) |
| { // reuse the old paramter |
| ((DBCmdParam)chk.value).setValue(expr.value); |
| expr.value = chk.value; |
| chk.value = null; |
| } |
| else |
| { // create new one |
| expr.value = addParam(expr.column.getDataType(), expr.value); |
| } |
| } |
| else |
| { // remove from parameter list (if necessary) |
| if (cmdParams!=null && (chk.value instanceof DBCmdParam)) |
| cmdParams.remove(chk.value); |
| } |
| // replace now |
| set.set(i, expr); |
| return this; |
| } |
| } |
| // Replace with parameter |
| if (useCmdParam(expr.column, expr.value)) |
| expr.value = addParam(expr.column.getDataType(), expr.value); |
| // new Value! |
| set.add(expr); |
| return this; |
| } |
| |
| /** |
| * Adds a list of set expressions to this command |
| * Use column.to(...) to create a set expression |
| * |
| * @param expr the DBSetExpr object(s) |
| * @return itself (this) |
| */ |
| public final DBCommand set(DBSetExpr... exprs) |
| { |
| for (int i=0; i<exprs.length; i++) |
| set(exprs[i]); |
| return this; |
| } |
| |
| /** |
| * Returns whether or not the command has group by set |
| */ |
| public boolean hasSetExpr() |
| { |
| return (this.set!=null ? !this.set.isEmpty() : false); |
| } |
| |
| /** |
| * Checks whether a column is in the list of set expressions |
| * @param column |
| * @return <code>true</code> if there is a set expression |
| */ |
| protected boolean hasSetExprOn(DBColumn column) |
| { |
| if (set==null) |
| return false; |
| for (DBSetExpr setExpr : set) |
| { // Find column |
| if (setExpr.column.equals(column)) |
| return true; |
| |
| } |
| return false; |
| } |
| |
| /** |
| * Returns all set expressions as unmodifiable list |
| * @return the list of DBSetExpr used for set |
| */ |
| public List<DBSetExpr> getSetExpressions() |
| { |
| return (this.set!=null ? Collections.unmodifiableList(this.set) : null); |
| } |
| |
| /** |
| * Adds an command parameter which will be used in a prepared statement. |
| * The command parameter returned may be used to alter the value. |
| * |
| * @param type the data type of the parameter |
| * @param value the initial parameter value |
| * |
| * @return the command parameter object |
| */ |
| public DBCmdParam addParam(DataType type, Object value) |
| { |
| if (cmdParams==null) |
| cmdParams= new ArrayList<DBCmdParam>(); |
| // Create and add the parameter to the parameter list |
| DBCmdParam param = new DBCmdParam(this, type, value); |
| cmdParams.add(param); |
| // done |
| return param; |
| } |
| |
| /** |
| * Adds an command parameter which will be used in a prepared statement. |
| * The initial value of the command parameter is null but can be modified using the setValue method. |
| * |
| * @param colExpr the column expression for which to create the parameter |
| * @param value the initial parameter value |
| * |
| * @return the command parameter object |
| */ |
| public final DBCmdParam addParam(DBColumnExpr colExpr, Object value) |
| { |
| return addParam(colExpr.getDataType(), value); |
| } |
| |
| /** |
| * Adds an command parameter which will be used in a prepared statement. |
| * The initial value of the command parameter is null but can be modified using the setValue method. |
| * |
| * @return the command parameter object |
| */ |
| public final DBCmdParam addParam(Object value) |
| { |
| return addParam(DataType.UNKNOWN, value); |
| } |
| |
| /** |
| * Adds an command parameter which will be used in a prepared statement. |
| * The initial value of the command parameter is null but can be modified using the setValue method. |
| * |
| * @return the command parameter object |
| */ |
| public final DBCmdParam addParam() |
| { |
| return addParam(DataType.UNKNOWN, null); |
| } |
| |
| /** |
| * Adds a join to the list of join expressions. |
| * |
| * @param join the join expression |
| * @return itself (this) |
| */ |
| public DBCommand join(DBJoinExpr join) |
| { |
| // check tables |
| if (join.getLeftTable().equals(join.getRightTable())) |
| throw new InvalidArgumentException("left|right", join.getLeftTable()); |
| // create list |
| if (joins == null) |
| joins = new ArrayList<DBJoinExpr>(); |
| // Create a new join |
| for (int i = 0; i < joins.size(); i++) |
| { // Check whether join exists |
| DBJoinExpr item = joins.get(i); |
| if (item.equals(join)) |
| return this; |
| } |
| joins.add(join); |
| return this; |
| } |
| |
| /** |
| * Adds an inner join based on two columns to the list of join expressions. |
| * |
| * @param left the left join value |
| * @param right the right join |
| * @return itself (this) |
| */ |
| public final DBCommand join(DBColumnExpr left, DBColumn right, DBCompareExpr... addlConstraints) |
| { |
| return join(left, right, DBJoinType.INNER, addlConstraints); |
| } |
| |
| /** |
| * Adds a left join based on two columns to the list of join expressions. |
| * Added for convenience |
| * Same as join(left, right, DBJoinType.LEFT); |
| * |
| * @param left the left join value |
| * @param right the right join |
| * @return itself (this) |
| */ |
| public final DBCommand joinLeft(DBColumnExpr left, DBColumn right, DBCompareExpr... addlConstraints) |
| { |
| return join(left, right, DBJoinType.LEFT, addlConstraints); |
| } |
| |
| /** |
| * Adds a right join based on two columns to the list of join expressions. |
| * Added for convenience |
| * Same as join(left, right, DBJoinType.RIGHT); |
| * |
| * @param left the left join value |
| * @param right the right join |
| * @return itself (this) |
| */ |
| public final DBCommand joinRight(DBColumnExpr left, DBColumn right, DBCompareExpr... addlConstraints) |
| { |
| return join(left, right, DBJoinType.RIGHT, addlConstraints); |
| } |
| |
| /** |
| * Adds a join based on two columns to the list of join expressions. |
| * |
| * Migration hint from 2.x -> replace ").where(" with just "," |
| * |
| * @param left the left join value |
| * @param right the right join |
| * @param joinType type of join ({@link DBJoinType#INNER}, {@link DBJoinType#LEFT}, {@link DBJoinType#RIGHT}) |
| * @return itself (this) |
| */ |
| public final DBCommand join(DBColumnExpr left, DBColumn right, DBJoinType joinType, DBCompareExpr... addlConstraints) |
| { |
| if (left==null || right==null || left.getSourceColumn()==null) |
| throw new InvalidArgumentException("left|right", left); |
| if (left.getSourceColumn().getRowSet()==right.getRowSet()) |
| throw new InvalidArgumentException("rowset", left.getSourceColumn().getRowSet().getName()+"|"+right.getRowSet().getName()); |
| // create the expression |
| DBColumnJoinExpr join = new DBColumnJoinExpr(left, right, joinType); |
| // additional constraints |
| DBCompareExpr where = null; |
| for (int i=0; i<addlConstraints.length; i++) |
| { |
| DBCompareExpr cmpExpr = addlConstraints[i]; |
| if (cmpExpr==null) |
| continue; |
| // Check if prepared statements are enabled |
| if (isPreparedStatementsEnabled()) |
| { // use command params |
| cmpExpr.prepareCommand(this); |
| } |
| // Chain with previouss |
| where = (where!=null ? where.and(cmpExpr) : cmpExpr); |
| } |
| if (where!=null) |
| join.where(where); |
| // done |
| join(join); |
| return this; |
| } |
| |
| /** |
| * Multi-Column version of column based join expression |
| * @param left the columsn on the left |
| * @param right the columns on the right |
| * @param joinType the joinType |
| * @param addlConstraints addlConstraints |
| * @return itself (this) |
| */ |
| public final DBCommand join(DBColumn[] left, DBColumn[] right, DBJoinType joinType, DBCompareExpr... addlConstraints) |
| { |
| // check params |
| if (left==null || right==null || left.length==0 || left.length!=right.length) |
| throw new InvalidArgumentException("left|right", left); |
| if (left[0].getRowSet()==right[0].getRowSet()) |
| throw new InvalidArgumentException("rowset", left[0].getSourceColumn().getRowSet().getName()+"|"+right[0].getRowSet().getName()); |
| /* |
| * TODO: Find a better solution / Make DBColumnJoinExpr multi-column |
| */ |
| DBColumnJoinExpr join = new DBColumnJoinExpr(left[0], right[0], joinType); |
| // compare the columns except the first |
| DBCompareExpr where = null; |
| for (int i=1; i<left.length; i++) |
| { // add to where list |
| DBCompareExpr cmpExpr = right[i].is(left[i]); |
| // Check if prepared statements are enabled |
| if (isPreparedStatementsEnabled()) |
| { // use command params |
| cmpExpr.prepareCommand(this); |
| } |
| where = (where!=null ? where.and(cmpExpr) : cmpExpr); |
| } |
| // additional constraints |
| for (int i=0; i<addlConstraints.length; i++) |
| { |
| DBCompareExpr cmpExpr = addlConstraints[i]; |
| // Check if prepared statements are enabled |
| if (isPreparedStatementsEnabled()) |
| { // use command params |
| cmpExpr.prepareCommand(this); |
| } |
| where = (where!=null ? where.and(cmpExpr) : cmpExpr); |
| } |
| if (where!=null) |
| join.where(where); |
| // done |
| join(join); |
| return this; |
| } |
| |
| /** |
| * Adds a cross join for two tables or views |
| * @param left the left RowSet |
| * @param right the right RowSet |
| * @return itself (this) |
| */ |
| public final DBCommand join(DBRowSet left, DBRowSet right) |
| { |
| DBCrossJoinExpr join = new DBCrossJoinExpr(left, right); |
| join(join); |
| // done |
| return this; |
| } |
| |
| /** |
| * Adds a join based on a compare expression to the command. |
| * |
| * @param rowset table or view to join |
| * @param cmp the compare expression with which to join the table |
| * @param joinType type of join ({@link DBJoinType#INNER}, {@link DBJoinType#LEFT}, {@link DBJoinType#RIGHT}) |
| * @return itself (this) |
| */ |
| public final DBCommand join(DBRowSet rowset, DBCompareExpr cmp, DBJoinType joinType) |
| { |
| DBCompareJoinExpr join = new DBCompareJoinExpr(rowset, cmp, joinType); |
| join(join); |
| return this; |
| } |
| |
| /** |
| * Adds an inner join based on a compare expression to the command. |
| * |
| * @param rowset table of view which to join |
| * @param cmp the compare expression with wich to join the table |
| * @return itself (this) |
| */ |
| public final DBCommand join(DBRowSet rowset, DBCompareExpr cmp) |
| { |
| return join(rowset, cmp, DBJoinType.INNER); |
| } |
| |
| /** |
| * Adds a list of join expressions to the command. |
| * |
| * @param joinExprList list of join expressions |
| */ |
| public void addJoins(List<DBJoinExpr> joinExprList) |
| { |
| if (joins == null) |
| { |
| joins = new ArrayList<DBJoinExpr>(); |
| } |
| this.joins.addAll(joinExprList); |
| } |
| |
| /** |
| * Returns true if the command has a join on the given table or false otherwise. |
| * |
| * @param rowset rowset table or view to join |
| * |
| * @return true if the command has a join on the given table or false otherwise |
| */ |
| public boolean hasJoinOn(DBRowSet rowset) |
| { |
| if (joins==null) |
| return false; |
| // Examine all joins |
| for (DBJoinExpr join : joins) |
| { |
| if (join.isJoinOn(rowset)) |
| return true; |
| } |
| // not found |
| return false; |
| } |
| |
| /** |
| * Returns true if the command has a constraint on the given table or false otherwise. |
| * |
| * @param rowset rowset table or view to join |
| * |
| * @return true if the command has a join on the given table or false otherwise |
| */ |
| public boolean hasConstraintOn(DBRowSet rowset) |
| { |
| if (where==null && having==null) |
| return false; |
| // Examine all constraints |
| int i = 0; |
| Set<DBColumn> columns = new HashSet<DBColumn>(); |
| for (i = 0; where != null && i < where.size(); i++) |
| ((DBExpr) where.get(i)).addReferencedColumns(columns); |
| for (i = 0; having != null && i < having.size(); i++) |
| ((DBExpr) having.get(i)).addReferencedColumns(columns); |
| // now we have all columns |
| Iterator<DBColumn> iterator = columns.iterator(); |
| while (iterator.hasNext()) |
| { // get the table |
| DBColumn col = iterator.next(); |
| DBRowSet table = col.getRowSet(); |
| if (table.equals(rowset)) |
| return true; |
| } |
| // not found |
| return false; |
| } |
| |
| /** |
| * Returns true if the command has a join on the given column or false otherwise. |
| * |
| * @param column the column to test |
| * |
| * @return true if the command has a join on the given column or false otherwise |
| */ |
| public boolean hasJoinOn(DBColumn column) |
| { |
| if (joins==null) |
| return false; |
| // Examine all joins |
| for (DBJoinExpr join : joins) |
| { |
| if (join.isJoinOn(column)) |
| return true; |
| } |
| // not found |
| return false; |
| } |
| |
| /** |
| * removes all joins to a given table or view |
| * |
| * @param rowset the table or view for which to remove all joins |
| * |
| * @return true if any joins have been removed or false otherwise |
| */ |
| public boolean removeJoinsOn(DBRowSet rowset) |
| { |
| if (joins==null) |
| return false; |
| // Examine all joins |
| int size = joins.size(); |
| for (int i=size-1; i>=0; i--) |
| { |
| if (joins.get(i).isJoinOn(rowset)) |
| joins.remove(i); |
| } |
| return (size!=joins.size()); |
| } |
| |
| /** |
| * removes all joins to a given column |
| * |
| * @param column the column for which to remove all joins |
| * |
| * @return true if any joins have been removed or false otherwise |
| */ |
| public boolean removeJoinsOn(DBColumn column) |
| { |
| if (joins==null) |
| return false; |
| // Examine all joins |
| int size = joins.size(); |
| for (int i=size-1; i>=0; i--) |
| { |
| if (joins.get(i).isJoinOn(column)) |
| joins.remove(i); |
| } |
| return (size!=joins.size()); |
| } |
| |
| /** |
| * Adds a constraint to the where phrase of the sql statement |
| * If another restriction already exists for the same column it will be replaced. |
| * |
| * @param expr the DBCompareExpr object |
| * @return itself (this) |
| */ |
| public DBCommand where(DBCompareExpr expr) |
| { |
| if (where == null) |
| where = new ArrayList<DBCompareExpr>(); |
| setConstraint(where, expr); |
| return this; |
| } |
| |
| /** |
| * Adds a list of constraints to the where phrase of the sql statement |
| * If another restriction already exists for the same column it will be replaced. |
| * |
| * @param expr the DBCompareExpr object |
| * @return itself (this) |
| */ |
| public final DBCommand where(DBCompareExpr... exprs) |
| { |
| for (int i=0; i<exprs.length; i++) |
| where(exprs[i]); |
| return this; |
| } |
| |
| /** |
| * Returns true if the command has constraints or false if not. |
| * |
| * @return true if constraints have been set on the command |
| */ |
| public boolean hasWhereConstraints() |
| { |
| return (where!=null && where.size()>0); |
| } |
| |
| /** |
| * Returns a copy of the defined where clauses. |
| * |
| * @return vector of where clauses |
| */ |
| public List<DBCompareExpr> getWhereConstraints() |
| { |
| return (this.where!=null ? Collections.unmodifiableList(this.where) : null); |
| } |
| |
| /** |
| * 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) |
| return; |
| removeConstraintOn(where, col); |
| } |
| |
| /** |
| * Checks whether the command has a constraint on a particular column expression |
| * @param col the column expression which to check |
| */ |
| public boolean hasWhereConstraintOn(DBColumnExpr col) |
| { |
| if (where == null) |
| return false; |
| return hasConstraintOn(where, col); |
| } |
| |
| /** |
| * Returns a copy of the defined joins. |
| * |
| * @return the list of joins |
| */ |
| public List<DBJoinExpr> getJoins() |
| { |
| return (this.joins!=null ? Collections.unmodifiableList(this.joins) : null); |
| } |
| |
| /** |
| * Adds a list of constraints to the command. |
| * @param constraints list of constraints |
| */ |
| public void addWhereConstraints(List<DBCompareExpr> constraints) |
| { |
| // allocate |
| if (where == null) |
| where = new ArrayList<DBCompareExpr>(); |
| // add |
| this.where.addAll(constraints); |
| } |
| |
| /** |
| * adds a constraint to the having clause. |
| * @param expr the DBCompareExpr object |
| * @return itself (this) |
| */ |
| public DBCommand having(DBCompareExpr expr) |
| { |
| if (having == null) |
| having = new ArrayList<DBCompareExpr>(); |
| setConstraint(having, expr); |
| return this; |
| } |
| |
| /** |
| * Returns true if the command has having-constraints or false if not. |
| * |
| * @return true if constraints have been set on the command |
| */ |
| public boolean hasHavingConstraints() |
| { |
| return (having!=null && having.size()>0); |
| } |
| |
| /** |
| * Returns a copy of the defined having clauses. |
| * |
| * @return list of having constraints |
| */ |
| public List<DBCompareExpr> getHavingConstraints() |
| { |
| return (this.having!=null ? Collections.unmodifiableList(this.having) : null); |
| } |
| |
| /** |
| * 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 |
| */ |
| public void removeHavingConstraintOn(DBColumnExpr col) |
| { |
| if (having == null) |
| return; |
| removeConstraintOn(having, col); |
| } |
| |
| /** |
| * Checks whether the command has a constraint on a particular column expression |
| * @param col the column expression which to check |
| */ |
| public boolean hasHavingConstraintOn(DBColumnExpr col) |
| { |
| if (where == null) |
| return false; |
| return hasConstraintOn(having, col); |
| } |
| |
| /** |
| * Returns whether or not the command has group by set |
| */ |
| public boolean hasGroupBy() |
| { |
| return (this.groupBy!=null ? !this.groupBy.isEmpty() : false); |
| } |
| |
| /** |
| * Returns a copy of the defined where clauses. |
| * |
| * @return vector of where clauses |
| */ |
| public List<DBColumnExpr> getGroupBy() |
| { |
| return (this.groupBy!=null ? Collections.unmodifiableList(this.groupBy) : null); |
| } |
| |
| /** |
| * Adds a column expression to the Group By clause of an sql statement. |
| * |
| * @param columnExpr the column expression |
| * @return itself (this) |
| */ |
| public DBCommand groupBy(DBColumnExpr columnExpr) |
| { |
| if (groupBy == null) |
| groupBy = new ArrayList<DBColumnExpr>(); |
| // Add all |
| if (columnExpr.isAggregate()) |
| return this; |
| // Unwrap DBAliasExpr only |
| if (columnExpr instanceof DBAliasExpr) |
| columnExpr = ((DBAliasExpr)columnExpr).unwrap(); |
| // Already present? |
| if (groupBy.contains(columnExpr)) |
| return this; |
| // add |
| groupBy.add(columnExpr); |
| // done |
| return this; |
| } |
| |
| /** |
| * Adds a list of columns to the Group By clause of an sql statement. |
| * |
| * @param exprs vararg of columns by which to group the rows |
| * @return itself (this) |
| */ |
| public final DBCommand groupBy(DBColumnExpr...exprs) |
| { |
| for(DBColumnExpr expr : exprs) |
| { |
| groupBy(expr); |
| } |
| return this; |
| } |
| |
| /** |
| * Adds a collection of columns to the Group By clause of an sql statement. |
| * |
| * @param columns the column expressions to add |
| * @return itself (this) |
| */ |
| public final DBCommand groupBy(Collection<? extends DBColumnExpr> columns) |
| { |
| for (DBColumnExpr expr : columns) |
| { |
| groupBy(expr); |
| } |
| return this; |
| } |
| |
| /** |
| * Adds all select expressions which are not aggregates to the Group By clause |
| * @return itself (this) |
| */ |
| public final DBCommand groupAll() |
| { |
| clearGroupBy(); |
| // check select expression |
| if (select == null) |
| return this; |
| // make a group by array |
| for (DBColumnExpr expr : select) |
| { |
| if (expr.isAggregate()) |
| continue; // ignore aggregates |
| // append |
| groupBy(expr); |
| } |
| return this; |
| } |
| |
| /** |
| * Clears the select distinct option. |
| */ |
| public void clearSelectDistinct() |
| { |
| this.selectDistinct = false; |
| } |
| |
| /** |
| * Clears the list of selected columns. |
| */ |
| public void clearSelect() |
| { |
| select = null; |
| } |
| |
| /** |
| * Clears the Set clause |
| */ |
| public void clearSet() |
| { |
| if (set!=null && cmdParams!=null) |
| { // remove params |
| for (DBSetExpr set : this.set) |
| { // remove all |
| Object value = set.getValue(); |
| if (value instanceof DBCmdParam) |
| cmdParams.remove(value); |
| } |
| } |
| set = null; |
| } |
| |
| /** |
| * Clears the From / Join clause |
| */ |
| public void clearJoin() |
| { |
| joins = null; |
| } |
| |
| /** |
| * Removes all constraints from the Where clause |
| */ |
| public void clearWhere() |
| { |
| removeAllCommandParams(where); |
| where = null; |
| } |
| |
| /** |
| * Removes all constraints from the Having clause |
| */ |
| public void clearHaving() |
| { |
| removeAllCommandParams(having); |
| having = null; |
| } |
| |
| /** |
| * Clears the Group By clause |
| */ |
| public void clearGroupBy() |
| { |
| groupBy = null; |
| } |
| |
| /** |
| * Overridden to change return type from DBCommandExpr to DBCommand |
| */ |
| @Override |
| public DBCommand orderBy(DBOrderByExpr... exprs) |
| { |
| return (DBCommand)super.orderBy(exprs); |
| } |
| |
| /** |
| * Overridden to change return type from DBCommandExpr to DBCommand |
| */ |
| @Override |
| public DBCommand orderBy(DBColumnExpr... exprs) |
| { |
| return (DBCommand)super.orderBy(exprs); |
| } |
| |
| /** |
| * Overridden to change return type from DBCommandExpr to DBCommand |
| */ |
| @Override |
| public DBCommand orderBy(DBColumnExpr expr, boolean desc) |
| { |
| return (DBCommand)super.orderBy(expr, desc); |
| } |
| |
| /** |
| * Overridden to change return type from DBCommandExpr to DBCommand |
| */ |
| @Override |
| public DBCommand limitRows(int limitRows) |
| { |
| return (DBCommand)super.limitRows(limitRows); |
| } |
| |
| /** |
| * Overridden to change return type from DBCommandExpr to DBCommand |
| */ |
| @Override |
| public DBCommand skipRows(int skipRows) |
| { |
| return (DBCommand)super.skipRows(skipRows); |
| } |
| |
| /** |
| * Clears the entire command object. |
| */ |
| public void clear() |
| { |
| cmdParams = null; |
| clearSelectDistinct(); |
| clearSelect(); |
| clearSet(); |
| clearJoin(); |
| clearWhere(); |
| clearHaving(); |
| clearGroupBy(); |
| clearOrderBy(); |
| clearLimit(); |
| resetParamUsage(); |
| } |
| |
| /** |
| * returns true if prepared statements are enabled for this command |
| */ |
| protected boolean isPreparedStatementsEnabled() |
| { |
| return this.autoPrepareStmt; |
| } |
| |
| /** |
| * returns true if a cmdParam should be used for the given column or false otherwise |
| */ |
| protected boolean useCmdParam(DBColumnExpr col, Object value) |
| { |
| // Cannot wrap DBExpr or DBSystemDate |
| if (value==null || value instanceof DBExpr || value instanceof DBDatabase.DBSystemDate) |
| return false; |
| // Check if prepared statements are enabled |
| if (isPreparedStatementsEnabled()) |
| return true; |
| // Only use a command param if column is of type BLOB or CLOB |
| DataType dt = col.getDataType(); |
| return ( dt==DataType.BLOB || dt==DataType.CLOB ); |
| } |
| |
| /** |
| * adds a constraint to the 'where' or 'having' collections |
| * @param list the 'where' or 'having' list |
| * @param expr the DBCompareExpr object |
| */ |
| protected void setConstraint(List<DBCompareExpr> list, DBCompareExpr expr) |
| { |
| // Check if prepared statements are enabled |
| if (isPreparedStatementsEnabled()) |
| { // use command params |
| expr.prepareCommand(this); |
| } |
| // adds a comparison to the where or having list |
| for (int i = 0; i < list.size(); i++) |
| { // check expression |
| DBCompareExpr other = list.get(i); |
| if (expr.isMutuallyExclusive(other)==false) |
| continue; |
| // Check if we replace a DBCommandParam |
| removeCommandParams(other); |
| // columns match |
| list.set(i, expr); |
| return; |
| } |
| // add expression |
| list.add(expr); |
| } |
| |
| /** |
| * 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 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 boolean hasConstraintOn(List<DBCompareExpr> list, DBColumnExpr colExpr) |
| { |
| if (list == null) |
| return false; |
| for (DBCompareExpr cmp : list) |
| { // Check whether it is a compare column expr. |
| if (!(cmp instanceof DBCompareColExpr)) |
| continue; |
| // Compare columns |
| DBColumnExpr cmpCol = ((DBCompareColExpr)cmp).getColumnExpr(); |
| if (ObjectUtils.compareEqual(cmpCol, colExpr)) |
| return true; |
| // Update column |
| if ((colExpr instanceof DBColumn) && !(cmpCol instanceof DBColumn) && colExpr.equals(colExpr.getUpdateColumn())) |
| return true; |
| } |
| return false; |
| } |
| |
| /** |
| * 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) |
| { // Check whether it is a compare column expr. |
| if (!(cmp instanceof DBCompareColExpr)) |
| continue; |
| // Compare columns |
| DBColumnExpr cmpCol = ((DBCompareColExpr)cmp).getColumnExpr(); |
| if (ObjectUtils.compareEqual(cmpCol, colExpr)) |
| { // Check if we replace a DBCommandParam |
| 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; |
| } |
| } |
| } |
| |
| /** |
| * Gets a list of all tables referenced by the query. |
| * |
| * @return list of all rowsets (tables or views) used by the query |
| */ |
| protected List<DBRowSet> getRowSetList() |
| { |
| // Check all tables |
| int i = 0; |
| Set<DBColumn> columns = new HashSet<DBColumn>(); |
| for (i = 0; select != null && i < select.size(); i++) |
| ((DBExpr) select.get(i)).addReferencedColumns(columns); |
| for (i = 0; joins != null && i < joins.size(); i++) |
| ((DBExpr) joins.get(i)).addReferencedColumns(columns); |
| for (i = 0; where != null && i < where.size(); i++) |
| ((DBExpr) where.get(i)).addReferencedColumns(columns); |
| for (i = 0; groupBy != null && i < groupBy.size(); i++) |
| ((DBExpr) groupBy.get(i)).addReferencedColumns(columns); |
| for (i = 0; having != null && i < having.size(); i++) |
| ((DBExpr) having.get(i)).addReferencedColumns(columns); |
| for (i = 0; orderBy != null && i < orderBy.size(); i++) |
| ((DBExpr) orderBy.get(i)).addReferencedColumns(columns); |
| // now we have all columns |
| List<DBRowSet> tables = new ArrayList<DBRowSet>(); |
| Iterator<DBColumn> iterator = columns.iterator(); |
| while (iterator.hasNext()) |
| { // get the table |
| DBColumn col = iterator.next(); |
| DBRowSet table = col.getRowSet(); |
| if (table == cmdQuery) |
| { // Recursion |
| log.error("Recursive Column Selection in Command!"); |
| continue; |
| } |
| if (tables.contains(table) == false && table != null) |
| { // Add table |
| tables.add(table); |
| } |
| } |
| return tables; |
| } |
| |
| /** |
| * Adds Columns |
| */ |
| @Override |
| public void addReferencedColumns(Set<DBColumn> list) |
| { |
| // nothing to do! |
| return; |
| } |
| |
| /** |
| * Returns an array of parameter values for a prepared statement. |
| * 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 || paramUsageCount==0) |
| return null; |
| // Check whether all parameters have been used |
| 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[paramUsageCount]; |
| for (int i=0; i<values.length; i++) |
| values[i]=cmdParams.get(i).getValue(); |
| // values |
| return values; |
| } |
| |
| /** |
| * Creates a select SQL-Statement |
| * |
| * @return a select SQL-Statement |
| */ |
| @Override |
| public void getSelect(StringBuilder buf) |
| { |
| resetParamUsage(); |
| if (select == null) |
| throw new ObjectNotValidException(this); // invalid! |
| // Prepares statement |
| addSelect(buf); |
| // From clause |
| addFrom(buf); |
| // Add Where |
| addWhere(buf); |
| // Add Grouping |
| addGrouping(buf); |
| // Add Order |
| addOrder(buf); |
| // done |
| completeParamUsage(); |
| } |
| |
| /** |
| * Creates an insert SQL-Statement |
| * |
| * @return an insert SQL-Statement |
| */ |
| // get Insert |
| public String getInsert() |
| { |
| resetParamUsage(); |
| if (set==null || set.get(0)==null) |
| return null; |
| StringBuilder buf = new StringBuilder("INSERT INTO "); |
| // addTableExpr(buf, CTX_NAME); |
| DBRowSet table = set.get(0).getTable(); |
| table.addSQL(buf, CTX_FULLNAME); |
| // Set Expressions |
| buf.append("( "); |
| // Set Expressions |
| ArrayList<DBCompareColExpr> compexpr = null; |
| if (where!=null && !where.isEmpty()) |
| { // Convert ColumnExpression List to Column List |
| compexpr = new ArrayList<DBCompareColExpr>(where.size()); |
| for (DBCompareExpr expr : where) |
| { |
| appendCompareColExprs(table, expr, compexpr); |
| } |
| // Add Column Names from where clause |
| if (compexpr.size()>0) |
| { |
| // add List |
| addListExpr(buf, compexpr, CTX_NAME, ", "); |
| // add separator |
| if (set != null) |
| buf.append(", "); |
| } |
| else |
| { // No columns to set |
| compexpr = null; |
| } |
| } |
| if (set != null) |
| addListExpr(buf, set, CTX_NAME, ", "); |
| // Values |
| buf.append(") VALUES ( "); |
| if (compexpr != null) |
| addListExpr(buf, compexpr, CTX_VALUE, ", "); |
| if (compexpr != null && set != null) |
| buf.append(", "); |
| if (set != null) |
| addListExpr(buf, set, CTX_VALUE, ", "); |
| // End |
| buf.append(")"); |
| // done |
| completeParamUsage(); |
| return buf.toString(); |
| } |
| |
| /** |
| * Appends all nested DBCompareColExpr for a particular RowSet to a list |
| * @param table the rowset for which to collect the DBCompareColExpr |
| * @param expr a compare expression |
| * @param list |
| */ |
| protected void appendCompareColExprs(DBRowSet table, DBCompareExpr expr, List<DBCompareColExpr> list) |
| { |
| if (expr instanceof DBCompareColExpr) |
| { // DBCompareColExpr |
| DBColumn column = ((DBCompareColExpr)expr).getColumnExpr().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); |
| } |
| else if (ObjectUtils.isWrapper(expr)) |
| { // unwrap |
| appendCompareColExprs(table, ObjectUtils.unwrap(expr), list); |
| } |
| } |
| |
| /** |
| * Creates an update SQL-Statement |
| * |
| * @return an update SQL-Statement |
| */ |
| public final String getUpdate() |
| { |
| resetParamUsage(); |
| if (set == null) |
| return null; |
| StringBuilder buf = new StringBuilder("UPDATE "); |
| DBRowSet table = set.get(0).getTable(); |
| if (joins!=null && !joins.isEmpty()) |
| { // Join Update |
| addUpdateWithJoins(buf, table); |
| } |
| else |
| { // Simple Statement |
| addUpdateForTable(buf, table); |
| } |
| // done |
| completeParamUsage(); |
| return buf.toString(); |
| } |
| |
| protected void addUpdateForTable(StringBuilder buf, DBRowSet table) |
| { // Simple Statement |
| table.addSQL(buf, CTX_FULLNAME); |
| long context = CTX_NAME | CTX_VALUE; |
| // Set Expressions |
| buf.append("\r\nSET "); |
| addListExpr(buf, set, context, ", "); |
| // Add Where |
| addWhere(buf, context); |
| } |
| |
| protected void addUpdateWithJoins(StringBuilder buf, DBRowSet table) |
| { // Join Update |
| buf.append( table.getAlias() ); |
| long context = CTX_DEFAULT; |
| // Set Expressions |
| buf.append("\r\nSET "); |
| addListExpr(buf, set, context, ", "); |
| // From clause |
| addFrom(buf); |
| // Add Where |
| addWhere(buf, context); |
| } |
| |
| /** |
| * Creates a delete SQL-Statement |
| * |
| * @param table the table object |
| * |
| * @return a delete SQL-Statement |
| */ |
| public final String getDelete(DBTable table) |
| { |
| resetParamUsage(); |
| StringBuilder buf = new StringBuilder("DELETE "); |
| // joins or simple |
| if (joins!=null && !joins.isEmpty()) |
| { // delete with joins |
| addDeleteWithJoins(buf, table); |
| } |
| else |
| { // Simple Statement |
| addDeleteForTable(buf, table); |
| } |
| // done |
| completeParamUsage(); |
| return buf.toString(); |
| } |
| |
| protected void addDeleteForTable(StringBuilder buf, DBRowSet table) |
| { // Simple Statement |
| buf.append("FROM "); |
| table.addSQL(buf, CTX_FULLNAME); |
| // where |
| addWhere(buf, CTX_NAME|CTX_VALUE); |
| } |
| |
| protected void addDeleteWithJoins(StringBuilder buf, DBRowSet table) |
| { // delete with joins |
| table.addSQL(buf, CTX_FULLNAME); |
| // From clause |
| addFrom(buf); |
| // Add Where |
| addWhere(buf, CTX_DEFAULT); |
| } |
| |
| // ------- Select Statement Parts ------- |
| |
| protected void addSelect(StringBuilder buf) |
| { |
| // Prepares statement |
| buf.append("SELECT "); |
| if (selectDistinct) |
| buf.append("DISTINCT "); |
| // Add Select Expressions |
| addListExpr(buf, select, CTX_ALL, ", "); |
| } |
| |
| protected void addFrom(StringBuilder buf) |
| { |
| int originalLength = buf.length(); |
| buf.append("\r\nFROM "); |
| // Join |
| boolean sep = false; |
| int whichParams = 0; |
| List<DBRowSet> tables = getRowSetList(); |
| if (joins!=null && joins.size()>0) |
| { // Join |
| List<DBRowSet> joinTables = new ArrayList<DBRowSet>(); |
| for (int i=0; i<joins.size(); i++) |
| { // append join |
| long context; |
| DBJoinExpr join = joins.get(i); |
| if (i<1) |
| { // Add Join Tables |
| joinTables.add(join.getLeftTable()); |
| joinTables.add(join.getRightTable()); |
| // Remove from List |
| tables.remove(join.getLeftTable()); |
| tables.remove(join.getRightTable()); |
| // Context |
| context = CTX_NAME|CTX_VALUE; |
| whichParams = 0; |
| } |
| else |
| { // Extend the join |
| if (joinTables.contains(join.getRightTable())) |
| join.reverse(); |
| // Add Right Table |
| joinTables.add(join.getRightTable()); |
| tables .remove(join.getRightTable()); |
| // Context |
| context = CTX_VALUE; |
| buf.append( "\t" ); |
| whichParams = 1; |
| } |
| // check |
| addJoin(buf, join, context, whichParams); |
| // add CRLF |
| if( i!=joins.size()-1 ) |
| buf.append("\r\n"); |
| } |
| sep = true; |
| } |
| for (int i=0; i<tables.size(); i++) |
| { |
| if (sep) buf.append(", "); |
| DBRowSet t = tables.get(i); |
| t.addSQL(buf, CTX_DEFAULT|CTX_ALIAS); |
| // check for query |
| if (t instanceof DBQuery) |
| { // Merge subquery params |
| mergeSubqueryParams(((DBQuery)t).getCommandExpr().getParamValues()); |
| } |
| sep = true; |
| } |
| if (sep==false) |
| { // add pseudo table or omitt from |
| String pseudoTable = getDatabase().getDbms().getSQLPhrase(DBSqlPhrase.SQL_PSEUDO_TABLE); |
| if (StringUtils.isNotEmpty(pseudoTable)) |
| { // add pseudo table |
| buf.append(pseudoTable); |
| } |
| else |
| { // remove from |
| buf.setLength(originalLength); |
| } |
| } |
| } |
| |
| 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) |
| return; |
| // Subquery has parameters |
| if (cmdParams==null) |
| cmdParams= new ArrayList<DBCmdParam>(subQueryParams.length); |
| for (int p=0; p<subQueryParams.length; p++) |
| cmdParams.add(paramUsageCount++, new DBCmdParam(null, DataType.UNKNOWN, subQueryParams[p])); |
| } |
| |
| protected void addWhere(StringBuilder buf, long context) |
| { |
| if (where!=null && !where.isEmpty()) |
| { |
| buf.append("\r\nWHERE "); |
| // add where expression |
| addListExpr(buf, where, context, " AND "); |
| } |
| } |
| |
| protected final void addWhere(StringBuilder buf) |
| { |
| addWhere(buf, CTX_DEFAULT); |
| } |
| |
| protected void addGrouping(StringBuilder buf) |
| { |
| if (groupBy!=null && !groupBy.isEmpty()) |
| { // Group by |
| buf.append("\r\nGROUP BY "); |
| addListExpr(buf, groupBy, CTX_DEFAULT, ", "); |
| } |
| if (having!=null && !having.isEmpty()) |
| { // Having |
| buf.append("\r\nHAVING "); |
| addListExpr(buf, having, CTX_DEFAULT, " AND "); |
| } |
| } |
| |
| protected void addOrder(StringBuilder buf) |
| { |
| if (orderBy!=null && !orderBy.isEmpty()) |
| { // order By |
| buf.append("\r\nORDER BY "); |
| addListExpr(buf, orderBy, CTX_DEFAULT, ", "); |
| } |
| } |
| |
| } |