Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* 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 ro.nextreports.engine.querybuilder.sql;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.LinkedList;
import java.util.Map;
import java.io.ObjectStreamException;
import ro.nextreports.engine.querybuilder.sql.dialect.Dialect;
import ro.nextreports.engine.querybuilder.sql.output.Output;
import ro.nextreports.engine.querybuilder.sql.output.Outputable;
import ro.nextreports.engine.querybuilder.sql.output.ToStringer;
import ro.nextreports.engine.querybuilder.sql.util.CollectionUtil;
import ro.nextreports.engine.util.xstream.XStreamable;
/**
* @author Decebal Suiu
*/
public class SelectQuery implements Outputable, XStreamable {
private static final long serialVersionUID = -2137979893531895771L;
private static OrderIndexComparator orderIndexComparator = new OrderIndexComparator();
private boolean distinct;
private List columns;
private List criterias;
private List orders;
private List groupByColumns;
private LinkedList> orCriterias;
private transient Dialect dialect;
public SelectQuery() {
columns = new ArrayList();
criterias = new ArrayList();
LinkedList firstOr = new LinkedList();
orCriterias = new LinkedList>();
orCriterias.add(firstOr);
orders = new ArrayList();
groupByColumns = new ArrayList();
}
public boolean isDistinct() {
return distinct;
}
public void setDistinct(boolean distinct) {
this.distinct = distinct;
}
public void setDialect(Dialect dialect) {
this.dialect = dialect;
}
public void addColumn(Column column) {
columns.add(column);
}
public void addColumn(Column column, int index) {
addColumn(column);
moveColumn(column, index);
}
public void addColumn(Table table, String columname) {
addColumn(table.getColumn(columname));
}
public List getColumns(Table table) {
List result = new ArrayList();
for (Column column : columns) {
if (column.getTable().equals(table)) {
result.add(column);
}
}
return result;
}
public List getColumns() {
return columns;
}
public List getExpressionColumn() {
List list = new ArrayList();
for (Column column : columns) {
if (column instanceof ExpressionColumn) {
list.add((ExpressionColumn) column);
}
}
return list;
}
public boolean removeColumn(Column column) {
return columns.remove(column);
}
public boolean removeColumnAndDependencies(Column column) {
removeMatchCriteria(column);
removeOrMatchCriteria(column, 0);
removeGroupByColumn(column);
removeOrder(column);
return columns.remove(column);
}
public void changeColumn(Column oldColumn, Column newColumn) {
CollectionUtil.changeItem(columns, oldColumn, newColumn);
}
public void moveColumn(Column oldColumn, int newIndex) {
CollectionUtil.moveItem(columns, oldColumn, newIndex);
}
public int getColumnIndex(Column column) {
return columns.indexOf(column);
}
public List listColumns() {
return Collections.unmodifiableList(columns);
}
public int getColumnsCount() {
return columns.size();
}
public void addCriteria(Criteria criteria) {
this.criterias.add(criteria);
}
public MatchCriteria getMatchCriteria(Column column) {
for (Criteria criteria : criterias) {
if (criteria instanceof MatchCriteria) {
MatchCriteria mc = (MatchCriteria) criteria;
if (mc.getColumn().equals(column)) {
return mc;
}
}
}
return null;
}
public List getParameterMatchCriterias() {
List result = new ArrayList();
for (Criteria criteria : criterias) {
if (criteria instanceof MatchCriteria) {
MatchCriteria mc = (MatchCriteria) criteria;
if (mc.isParameter()) {
result.add(mc);
}
}
}
return result;
}
public void updateParameterMatchCriterias(List pmcList) {
for (MatchCriteria mc : pmcList) {
MatchCriteria oldmc = getMatchCriteria(mc.getColumn());
if ((oldmc != null) && mc.isParameter()) {
oldmc.setParameter(true);
}
if ((oldmc != null) && mc.isParameter2()) {
oldmc.setParameter2(true);
}
}
}
public void removeMatchCriterias(String tableAlias) {
for (Column column : columns) {
Table table = column.getTable();
if ((table != null) && table.getAlias().equals(tableAlias)) {
removeMatchCriteria(column);
}
}
}
public void removeMatchCriteria(Column column) {
MatchCriteria criteria = getMatchCriteria(column);
if (criteria != null) {
removeCriteria(criteria);
}
}
public boolean removeCriteria(Criteria criteria) {
return criterias.remove(criteria);
}
public LinkedList getOrList(int position) {
LinkedList or;
if (orCriterias.size() == 0) {
or = new LinkedList();
orCriterias.add(or);
return or;
}
or = orCriterias.get(position);
if (or == null) {
or = new LinkedList();
orCriterias.add(position, or);
}
return or;
}
public void addOrCriteria(Criteria criteria, int position) {
LinkedList or = getOrList(position);
or.add(criteria);
}
public MatchCriteria getOrMatchCriteria(Column column, int position) {
LinkedList or = getOrList(position);
for (Criteria criteria : or) {
if (criteria instanceof MatchCriteria) {
MatchCriteria mc = (MatchCriteria) criteria;
if (mc.getColumn().equals(column)) {
return mc;
}
}
}
return null;
}
public List getOrParameterMatchCriterias(int position) {
LinkedList or = getOrList(position);
List result = new ArrayList();
for (Criteria criteria : or) {
if (criteria instanceof MatchCriteria) {
MatchCriteria mc = (MatchCriteria) criteria;
if (mc.isParameter()) {
result.add(mc);
}
}
}
return result;
}
public void updateOrParameterMatchCriterias(List pmcList, int position) {
for (MatchCriteria mc : pmcList) {
MatchCriteria oldmc = getOrMatchCriteria(mc.getColumn(), position);
if ((oldmc != null) && mc.isParameter()) {
oldmc.setParameter(true);
}
if ((oldmc != null) && mc.isParameter2()) {
oldmc.setParameter2(true);
}
}
}
public void removeOrMatchCriterias(String tableAlias, int position) {
for (Column column : columns) {
Table table = column.getTable();
if ((table != null) && table.getAlias().equals(tableAlias)) {
removeOrMatchCriteria(column, position);
}
}
}
public void removeOrMatchCriteria(Column column, int position) {
MatchCriteria criteria = getOrMatchCriteria(column, position);
if (criteria != null) {
removeOrCriteria(criteria, position);
}
}
public boolean removeOrCriteria(Criteria criteria, int position) {
LinkedList or = getOrList(position);
return or.remove(criteria);
}
public void clear() {
columns.clear();
criterias.clear();
orCriterias.clear();
orders.clear();
groupByColumns.clear();
distinct = false;
}
public boolean containsCriteria(Criteria criteria) {
return criterias.contains(criteria);
}
public void changeCriteria(Criteria oldCriteria, Criteria newCriteria) {
CollectionUtil.changeItem(criterias, oldCriteria, newCriteria);
}
public List listCriterias() {
return Collections.unmodifiableList(criterias);
}
public int getCriteriasCount() {
return criterias.size();
}
public List getInnerJoins() {
List joins = new ArrayList();
for (Criteria criteria : criterias) {
if (criteria instanceof JoinCriteria) {
JoinCriteria jc = (JoinCriteria) criteria;
if (!JoinType.isOuter(jc.getJoinType())) {
joins.add(jc);
}
}
}
return joins;
}
public List getJoins() {
List joins = new ArrayList();
for (Criteria criteria : criterias) {
if (criteria instanceof JoinCriteria) {
joins.add((JoinCriteria) criteria);
}
}
return joins;
}
public List getNotJoins() {
List list = new ArrayList();
for (Criteria criteria : criterias) {
if (!(criteria instanceof JoinCriteria)) {
list.add(criteria);
}
}
return list;
}
public void addJoin(JoinCriteria join) {
addCriteria(join);
}
public JoinCriteria addJoin(Column srcColumn, Column destColumn) {
JoinCriteria jc = new JoinCriteria(srcColumn, destColumn);
addCriteria(jc);
return jc;
}
public void addJoin(Table srcTable, String srcColumnName, Table destTable,
String destColumnname) {
addCriteria(new JoinCriteria(srcTable.getColumn(srcColumnName),
destTable.getColumn(destColumnname)));
}
public void addOrder(Order order) {
orders.add(order);
}
public void addOrder(Column column, boolean ascending) {
addOrder(new Order(column, ascending));
}
public void addOrder(Table table, String columnName, boolean ascending) {
addOrder(new Order(table.getColumn(columnName), ascending));
}
public boolean removeOrder(Order order) {
return this.orders.remove(order);
}
public boolean removeOrder(Column column) {
return this.orders.remove(getOrder(column));
}
public List listOrders() {
return Collections.unmodifiableList(orders);
}
public List getOrders() {
return orders;
}
public void setOrders(List orders) {
this.orders = orders;
}
public int getOrdersCount() {
return orders.size();
}
public Order getOrder(Column column) {
for (Order order : orders) {
if (order.getColumn().equals(column)) {
return order;
}
}
return null;
}
public void addGroupByColumn(Column column) {
this.groupByColumns.add(column);
}
public void addGroupByColumn(Column column, int index) {
int size = groupByColumns.size();
// in column has output=false groupby columns may be not successive (and we must add nulls till
// the current index)
if (index > size) {
for (int i=size; i getNotNullGroupByColumns() {
List list = new ArrayList();
for (Column col : groupByColumns) {
if (col != null) {
list.add(col);
}
}
return list;
}
private int getGroupByColumnIndex(Column column) {
if (column instanceof GroupByFunctionColumn) {
GroupByFunctionColumn fc = (GroupByFunctionColumn) column;
for (int i = 0, size = groupByColumns.size(); i < size; i++) {
Column col = groupByColumns.get(i);
Table table = null;
if (col != null) {
table = col.getTable();
}
// table can be null for an ExpressionColumn
if (table == null) {
if ((col != null) && col.getName().equals(fc.getName())) {
return i;
}
} else {
if ((col != null) && table.equals(fc.getTable()) && col.getName().equals(fc.getName())) {
return i;
}
}
}
} else {
for (int i = 0, size = groupByColumns.size(); i < size; i++) {
Column col = groupByColumns.get(i);
if (col != null) {
if (col.getTable() == null) {
if ((col != null) && col.getName().equals(column.getName())) {
return i;
}
} else {
if ((col != null) && col.getTable().equals(column.getTable()) && col.getName().equals(column.getName())) {
return i;
}
}
}
}
}
return -1;
}
public List getGroupByColumns() {
return groupByColumns;
}
public boolean hasNotNullGroupByColumn() {
for (Column col : groupByColumns) {
if (col != null) {
return true;
}
}
return false;
}
public void setGroupByColumns(List groupByColumns) {
this.groupByColumns = groupByColumns;
}
public void removeGroupByColumns(String tableAlias) {
for (Column column : columns) {
Table table = column.getTable();
if ((table != null) && table.getAlias().equals(tableAlias)) {
int index = getGroupByColumnIndex(column);
if (index != -1) {
this.groupByColumns.set(index, null);
}
}
}
}
public boolean containsGroupByColumn(Column column) {
return this.groupByColumns.contains(column);
}
public void removeAllGroupByColumns() {
this.groupByColumns.clear();
}
public String toString() {
return ToStringer.toString(this);
}
public void write(Output out) {
if (this.columns.size() == 0) {
return;
}
if (this.distinct) {
out.println("SELECT DISTINCT");
} else {
out.println("SELECT");
}
// add columns to select
out.indent();
appendList(out, getOutputColumns(columns), ",", true);
out.println();
out.unindent();
// add tables to select from
out.println("FROM");
// determine all tables used in query
out.indent();
appendList(out, findAllUsedTablesInFrom(), ",", false);
out.println();
out.unindent();
// add criterias : 'joins', 'not joins', 'or criterias'
int orSize = 0;
if (this.orCriterias != null) {
orSize = this.orCriterias.get(0).size();
}
// inner joins are written in WHERE clause
// outer joins are written in Table class
List innerJoins = getInnerJoins();
List notJoins = getNotJoins();
if (innerJoins.size() > 0) {
out.println("WHERE");
out.indent();
appendList(out, innerJoins, " AND ", false);
if (notJoins.size() > 0) {
if (innerJoins.size() > 0) {
out.print(" AND ");
if (orSize > 0) {
out.println("(");
out.indent();
} else {
out.println();
}
}
if (orSize > 0) {
out.print("(");
}
appendList(out, notJoins, " AND ", false);
if (orSize > 0) {
out.println(")");
} else {
out.unindent();
}
} else {
out.println();
}
} else if (notJoins.size() > 0) {
out.println("WHERE");
out.indent();
if (orSize > 0) {
out.print("(");
}
appendList(out, notJoins, " AND ", false);
if (orSize > 0) {
out.println(")");
} else {
out.unindent();
}
}
if (orSize > 0) {
// no criterias : must add WHERE clause
if (this.criterias.size() == 0) {
out.println("WHERE");
out.indent();
}
if (notJoins.size() > 0) {
out.println(" OR ");
out.print("(");
} else if (innerJoins.size() > 0) {
out.println(" AND ");
out.print("(");
}
appendList(out, this.orCriterias.get(0), " AND ", false);
if ((notJoins.size() > 0) || (innerJoins.size() > 0)) {
out.println(")");
}
if (this.criterias.size() == 0) {
out.unindent();
}
}
if (notJoins.size() > 0) {
if (innerJoins.size() > 0) {
if (orSize > 0) {
out.unindent();
out.println(")");
} else {
out.println();
}
} else {
out.println();
}
}
if ((this.criterias.size() > 0) && (orSize > 0)) {
out.unindent();
}
// group by
if (this.groupByColumns.size() > 0) {
out.println("GROUP BY");
out.indent();
appendList(out, getNotNullGroupByColumns(), ",", false);
out.println();
out.unindent();
}
// add orders
if (this.orders.size() > 0) {
out.println("ORDER BY");
out.indent();
appendList(out, sortOrders(orders), ",", false);
out.println();
out.unindent();
}
}
/**
* Iterate through a Collection and append all entries (using .toString()) to
* a StringBuffer.
*/
private void appendList(Output out, Collection collection, String separator, boolean areColumns) {
Iterator it = collection.iterator();
boolean hasNext = it.hasNext();
//boolean areColumns = (columns == collection);
while (hasNext) {
Outputable sqlToken = (Outputable) it.next();
hasNext = it.hasNext();
sqlToken.write(out);
if (areColumns) {
Column column = (Column) sqlToken;
String columnAlias = column.getAlias();
if (columnAlias != null) {
out.print(" AS ");
out.print("\"");
out.print(columnAlias);
out.print("\"");
}
}
if (hasNext) {
out.print(separator);
out.println();
}
}
}
private List getOutputColumns(List columns) {
List result = new ArrayList();
for (Column column : columns) {
if (column.isOutput()) {
result.add(column);
}
}
return result;
}
/**
* Find all the tables used in the query in FROM clause (from columns, criterias and orders).
*
* @return List of {@link Table}s
*/
private List
findAllUsedTablesInFrom() {
List
allTables = new ArrayList
();
Map
> sourceMap = new HashMap
>();
Map
> destMap = new HashMap
>();
// see what tables are used in outer joins
for (Object criteria : criterias) {
try {
JoinCriteria joinCriteria = (JoinCriteria) criteria;
Table sourceTable = joinCriteria.getSource().getTable();
Table destTable = joinCriteria.getDestination().getTable();
List sourceList = sourceMap.get(sourceTable);
List destList = sourceMap.get(destTable);
if (sourceList == null) {
sourceList = new ArrayList();
sourceMap.put(sourceTable, sourceList);
}
sourceList.add(joinCriteria);
if (destList == null) {
destList = new ArrayList();
destMap.put(destTable, destList);
}
destList.add(joinCriteria);
} catch (ClassCastException ex) {
// not a JoinCriteria
}
}
// add tables from column selection
for (Column column : columns) {
Table table = column.getTable();
if (table != null) {
table.setDialect(dialect);
}
if (canAddTableToFromClause(table, destMap, allTables)) {
table.setJoins(sourceMap.get(table));
allTables.add(table);
}
}
// add tables from criterias
// it is possible that a table is used only in joins without any column selection from it
for (Object criteria : criterias) {
try {
JoinCriteria joinCriteria = (JoinCriteria) criteria;
Table sourceTable = joinCriteria.getSource().getTable();
Table destTable = joinCriteria.getDestination().getTable();
if (canAddTableToFromClause(sourceTable, destMap, allTables)) {
sourceTable.setJoins(sourceMap.get(sourceTable));
allTables.add(sourceTable);
}
if (canAddTableToFromClause(destTable, destMap, allTables)) {
destTable.setJoins(destMap.get(destTable));
allTables.add(destTable);
}
} catch (ClassCastException ex) {
// not a JoinCriteria
}
}
// add tables used by order columns
for (Order order : orders) {
Table table = order.getColumn().getTable();
if (table != null) {
table.setDialect(dialect);
}
if (canAddTableToFromClause(table, destMap, allTables)) {
allTables.add(table);
}
}
return allTables;
}
// if a table is used in destination of an outer join, it must not be added in the FROM clause
// outer joins are written in Table class
private boolean canAddTableToFromClause(Table table, Map
> destMap, List
allTables) {
if ((table == null) || allTables.contains(table)) {
return false;
}
if ((destMap.get(table) != null) && (destMap.get(table).size() > 0)) {
List list = destMap.get(table);
for (JoinCriteria jc : list) {
if (JoinType.isOuter(jc.getJoinType())) {
return false;
}
}
}
return true;
}
@SuppressWarnings("unchecked")
private List sortOrders(List orders) {
List sortedOrders = new ArrayList(orders);
Collections.sort(sortedOrders, orderIndexComparator);
return sortedOrders;
}
/**
* Compare orders by index.
*
* @author Decebal Suiu
*/
static class OrderIndexComparator implements Comparator {
public int compare(Object objectA, Object objectB) {
Order orderA = (Order) objectA;
Order orderB = (Order) objectB;
int indexA = orderA.getIndex();
int indexB = orderB.getIndex();
if (indexA < indexB) {
return -1;
} else if (indexA > indexB) {
return 1;
} else {
return 0;
}
}
}
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
SelectQuery that = (SelectQuery) o;
if (distinct != that.distinct) return false;
if (columns != null ? !columns.equals(that.columns) : that.columns != null) return false;
if (criterias != null && that.criterias != null && (!criterias.containsAll(that.criterias) ||
!that.criterias.containsAll(criterias))) return false;
if (groupByColumns != null ? !groupByColumns.equals(that.groupByColumns) : that.groupByColumns != null)
return false;
if (orCriterias != null ? !orCriterias.equals(that.orCriterias) : that.orCriterias != null) return false;
if (orders != null ? !orders.equals(that.orders) : that.orders != null) return false;
return true;
}
public int hashCode() {
int result;
result = (distinct ? 1 : 0);
result = 31 * result + (columns != null ? columns.hashCode() : 0);
result = 31 * result + (criterias != null ? criterias.hashCode() : 0);
result = 31 * result + (orders != null ? orders.hashCode() : 0);
result = 31 * result + (groupByColumns != null ? groupByColumns.hashCode() : 0);
result = 31 * result + (orCriterias != null ? orCriterias.hashCode() : 0);
return result;
}
private Object readResolve() throws ObjectStreamException {
// Read/initialize additional fields
if (orCriterias == null) {
LinkedList firstOr = new LinkedList();
orCriterias = new LinkedList>();
orCriterias.add(firstOr);
}
if (groupByColumns == null) {
groupByColumns = new ArrayList();
}
return this;
}
}