/*
* Copyright 2001-2008 Geert Bevin (gbevin[remove] at uwyn dot com)
* Licensed under the Apache License, Version 2.0 (the "License")
* $Id: Select.java 3918 2008-04-14 17:35:35Z gbevin $
*/
package com.uwyn.rife.database.queries;
import java.util.*;
import com.uwyn.rife.database.Datasource;
import com.uwyn.rife.database.capabilities.Capabilities;
import com.uwyn.rife.database.capabilities.Capability;
import com.uwyn.rife.database.exceptions.DbQueryException;
import com.uwyn.rife.database.exceptions.TableNameOrFieldsRequiredException;
import com.uwyn.rife.database.exceptions.UnsupportedSqlFeatureException;
import com.uwyn.rife.datastructures.EnumClass;
import com.uwyn.rife.site.Constrained;
import com.uwyn.rife.site.ConstrainedBean;
import com.uwyn.rife.site.ConstrainedUtils;
import com.uwyn.rife.template.Template;
import com.uwyn.rife.template.TemplateFactory;
import com.uwyn.rife.tools.StringUtils;
/**
* Object representation of a SQL "SELECT" query.
*
* <p>This object may be used to dynamically construct a SQL statement in a
* database-independent fashion. After it is finished, it may be executed using
* one of the query methods on {@link com.uwyn.rife.database.DbQueryManager
* DbQueryManager}.
*
* @author Geert Bevin (gbevin[remove] at uwyn dot com)
* @author Steven Grimm (koreth[remove] at midwinter dot com)
* @version $Revision: 3918 $
* @since 1.0
*/
public class Select extends AbstractWhereQuery<Select> implements Cloneable, ReadQuery
{
private String mHint = null;
private List<String> mFields = null;
private String mFrom = null;
private List<Join> mJoins = null;
private List<String> mGroupBy = null;
private List<String> mHaving = null;
private boolean mDistinct = false;
private List<String> mDistinctOn = null;
private List<Union> mUnions = null;
private List<OrderBy> mOrderBy = null;
private int mLimit = -1;
private int mOffset = -1;
private Capabilities mCapabilities = null;
private Class mConstrainedClass = null;
public static final JoinCondition NATURAL = new JoinCondition("NATURAL");
public static final JoinCondition ON = new JoinCondition("ON");
public static final JoinCondition USING = new JoinCondition("USING");
public static final JoinType LEFT = new JoinType("LEFT");
public static final JoinType RIGHT = new JoinType("RIGHT");
public static final JoinType FULL = new JoinType("FULL");
public static final OrderByDirection ASC = new OrderByDirection("ASC");
public static final OrderByDirection DESC = new OrderByDirection("DESC");
public Select(Datasource datasource)
{
this(datasource, null);
}
public Select(Datasource datasource, Class constrainedClass)
{
super(datasource);
if (null == datasource) throw new IllegalArgumentException("datasource can't be null.");
mConstrainedClass = constrainedClass;
clear();
}
public void clear()
{
super.clear();
mHint = null;
mFields = new ArrayList<String>();
mFrom = null;
mJoins = new ArrayList<Join>();
mGroupBy = new ArrayList<String>();
mHaving = new ArrayList<String>();
mDistinct = false;
mDistinctOn = new ArrayList<String>();
mUnions = new ArrayList<Union>();
mOrderBy = new ArrayList<OrderBy>();
mLimit = -1;
mOffset = -1;
mCapabilities = null;
assert 0 == mFields.size();
assert 0 == mJoins.size();
assert 0 == mGroupBy.size();
assert 0 == mHaving.size();
assert 0 == mDistinctOn.size();
assert 0 == mOrderBy.size();
}
public void clearGenerated()
{
super.clearGenerated();
mCapabilities = null;
}
public String getHint()
{
return mHint;
}
public Collection<String> getFields()
{
return mFields;
}
public boolean isDistinct()
{
return mDistinct;
}
public Collection<String> getDistinctOn()
{
return mDistinctOn;
}
public String getFrom()
{
return mFrom;
}
public Collection<Join> getJoins()
{
return mJoins;
}
public Collection<String> getGroupBy()
{
return mGroupBy;
}
public Collection<String> getHaving()
{
return mHaving;
}
public Collection<Union> getUnions()
{
return mUnions;
}
public Collection<OrderBy> getOrderBy()
{
return mOrderBy;
}
public int getLimit()
{
return mLimit;
}
public int getOffset()
{
return mOffset;
}
protected Template getTemplate()
{
return TemplateFactory.SQL.get("sql."+StringUtils.encodeClassname(mDatasource.getAliasedDriver())+".select");
}
public Capabilities getCapabilities()
{
if (null == mCapabilities)
{
Capabilities capabilities = null;
if (getLimit() != -1)
{
if (null == capabilities)
{
capabilities = new Capabilities();
}
capabilities.put(Capability.LIMIT, getLimit());
}
if (getLimitParameter() != null)
{
if (null == capabilities)
{
capabilities = new Capabilities();
}
capabilities.put(Capability.LIMIT_PARAMETER, getLimitParameter());
}
if (getOffset() != -1)
{
if (null == capabilities)
{
capabilities = new Capabilities();
}
capabilities.put(Capability.OFFSET, getOffset());
}
if (getOffsetParameter() != null)
{
if (null == capabilities)
{
capabilities = new Capabilities();
}
capabilities.put(Capability.OFFSET_PARAMETER, getOffsetParameter());
}
mCapabilities = capabilities;
}
return mCapabilities;
}
public String getSql()
throws DbQueryException
{
Constrained constrained = ConstrainedUtils.getConstrainedInstance(mConstrainedClass);
// handle constrained beans meta-data that needs to be handled after all the
// rest
if (constrained != null)
{
ConstrainedBean constrained_bean = constrained.getConstrainedBean();
if (constrained_bean != null)
{
// handle default ordering if no order statements have been
// defined yet
if (constrained_bean.hasDefaultOrdering() &&
0 == mOrderBy.size())
{
Iterator<ConstrainedBean.Order> ordering_it = constrained_bean.getDefaultOrdering().iterator();
ConstrainedBean.Order order = null;
while (ordering_it.hasNext())
{
order = ordering_it.next();
orderBy(order.getPropertyName(), OrderByDirection.getDirection(order.getDirection().toString()));
}
}
}
}
if (null == mFrom &&
0 == mFields.size())
{
throw new TableNameOrFieldsRequiredException("Select");
}
else
{
if (null == mSql)
{
Template template = getTemplate();
String block = null;
if (mHint != null)
{
if (!template.hasValueId("HINT"))
{
throw new UnsupportedSqlFeatureException("HINT", mDatasource.getAliasedDriver());
}
template.setValue("EXPRESSION", mHint);
template.setBlock("HINT", "HINT");
}
if (mDistinct)
{
if (0 == mDistinctOn.size())
{
block = template.getBlock("DISTINCT");
if (0 == block.length())
{
throw new UnsupportedSqlFeatureException("DISTINCT", mDatasource.getAliasedDriver());
}
template.setValue("DISTINCT", block);
}
else
{
if (template.hasValueId("COLUMNS"))
{
template.setValue("COLUMNS", StringUtils.join(mDistinctOn, template.getBlock("SEPERATOR")));
}
block = template.getBlock("DISTINCTON");
if (0 == block.length())
{
throw new UnsupportedSqlFeatureException("DISTINCT ON", mDatasource.getAliasedDriver());
}
template.setValue("DISTINCT", block);
}
}
if (0 == mFields.size())
{
template.setValue("FIELDS", template.getBlock("ALLFIELDS"));
}
else
{
template.setValue("FIELDS", StringUtils.join(mFields, template.getBlock("SEPERATOR")));
}
if (null != mFrom)
{
template.setValue("TABLE", mFrom);
block = template.getBlock("FROM");
if (0 == block.length())
{
throw new UnsupportedSqlFeatureException("FROM", mDatasource.getAliasedDriver());
}
template.setValue("FROM", block);
}
if (mJoins.size() > 0)
{
ArrayList<String> join_list = new ArrayList<String>();
for (Join join : mJoins)
{
join_list.add(join.getSql(template));
}
template.setValue("JOINS", StringUtils.join(join_list, ""));
}
if (mWhere.length() > 0)
{
template.setValue("CONDITION", mWhere);
block = template.getBlock("WHERE");
if (0 == block.length())
{
throw new UnsupportedSqlFeatureException("WHERE", mDatasource.getAliasedDriver());
}
template.setValue("WHERE", block);
}
if (mGroupBy.size() > 0)
{
template.setValue("EXPRESSION", StringUtils.join(mGroupBy, template.getBlock("SEPERATOR")));
block = template.getBlock("GROUPBY");
if (0 == block.length())
{
throw new UnsupportedSqlFeatureException("GROUP BY", mDatasource.getAliasedDriver());
}
template.setValue("GROUPBY", block);
}
if (mHaving.size() > 0)
{
template.setValue("EXPRESSION", StringUtils.join(mHaving, template.getBlock("SEPERATOR")));
block = template.getBlock("HAVING");
if (0 == block.length())
{
throw new UnsupportedSqlFeatureException("HAVING", mDatasource.getAliasedDriver());
}
template.setValue("HAVING", block);
}
if (mUnions != null)
{
for (Union union : mUnions)
{
template.setValue("EXPRESSION", union.getExpression());
if (union.isAll())
{
block = template.getBlock("UNION_ALL");
if (0 == block.length())
{
throw new UnsupportedSqlFeatureException("UNION_ALL", mDatasource.getAliasedDriver());
}
template.appendBlock("UNION", "UNION_ALL");
}
else
{
block = template.getBlock("UNION");
if (0 == block.length())
{
throw new UnsupportedSqlFeatureException("UNION", mDatasource.getAliasedDriver());
}
template.appendBlock("UNION", "UNION");
}
}
}
if (mOrderBy.size() > 0)
{
ArrayList<String> orderby_list = new ArrayList<String>();
for (OrderBy order_by : mOrderBy)
{
orderby_list.add(order_by.getSql(template));
}
template.setValue("ORDERBY_PARTS", StringUtils.join(orderby_list, template.getBlock("SEPERATOR")));
block = template.getBlock("ORDERBY");
if (0 == block.length())
{
throw new UnsupportedSqlFeatureException("ORDER BY", mDatasource.getAliasedDriver());
}
template.setValue("ORDERBY", block);
}
if (mLimit != -1 ||
getLimitParameter() != null)
{
// integrate a default value for offset if that has been provided
// by the template
if (-1 == mOffset &&
template.hasValueId("OFFSET_VALUE"))
{
String offset_value = template.getValue("OFFSET_VALUE");
if (offset_value != null &&
offset_value.trim().length() > 0)
{
mOffset = Integer.parseInt(offset_value);
}
}
if (mOffset > -1 ||
getOffsetParameter() != null)
{
if (template.hasValueId("OFFSET_VALUE"))
{
if (getOffsetParameter() != null)
{
template.setValue("OFFSET_VALUE", "?");
}
else
{
template.setValue("OFFSET_VALUE", mOffset);
}
}
block = template.getBlock("OFFSET");
if (0 == block.length())
{
if (!mExcludeUnsupportedCapabilities)
{
throw new UnsupportedSqlFeatureException("OFFSET", mDatasource.getAliasedDriver());
}
}
else
{
template.setValue("OFFSET", block);
}
}
if (template.hasValueId("LIMIT_VALUE"))
{
if (getLimitParameter() != null)
{
template.setValue("LIMIT_VALUE", "?");
}
else
{
template.setValue("LIMIT_VALUE", mLimit);
}
}
block = template.getBlock("LIMIT");
if (0 == block.length())
{
if (!mExcludeUnsupportedCapabilities)
{
throw new UnsupportedSqlFeatureException("LIMIT", mDatasource.getAliasedDriver());
}
}
else
{
template.setValue("LIMIT", block);
}
}
mSql = template.getBlock("QUERY");
assert mSql != null;
assert mSql.length() > 0;
}
}
return mSql;
}
public Select hint(String hint)
{
clearGenerated();
mHint = hint;
return this;
}
public Select field(String field)
{
if (null == field) throw new IllegalArgumentException("field can't be null.");
if (0 == field.length()) throw new IllegalArgumentException("field can't be empty.");
clearGenerated();
mFields.add(field);
return this;
}
public Select field(String alias, Select query)
{
if (null == alias) throw new IllegalArgumentException("alias can't be null.");
if (0 == alias.length()) throw new IllegalArgumentException("alias can't be empty.");
if (null == query) throw new IllegalArgumentException("query can't be null.");
StringBuilder buffer = new StringBuilder();
buffer.append("(");
buffer.append(query.toString());
buffer.append(") AS ");
buffer.append(alias);
field(buffer.toString());
fieldSubselect(query);
return this;
}
public Select fields(Class beanClass)
throws DbQueryException
{
return fieldsExcluded(null, beanClass, (String[])null);
}
public Select fieldsExcluded(Class beanClass, String... excludedFields)
throws DbQueryException
{
return fieldsExcluded(null, beanClass, excludedFields);
}
public Select fields(String table, Class beanClass)
throws DbQueryException
{
return fieldsExcluded(table, beanClass, (String[])null);
}
public Select fieldsExcluded(String table, Class beanClass, String... excludedFields)
throws DbQueryException
{
if (null == beanClass) throw new IllegalArgumentException("beanClass can't be null.");
Set<String> property_names = QueryHelper.getBeanPropertyNames(beanClass, excludedFields);
Constrained constrained = ConstrainedUtils.getConstrainedInstance(beanClass);
// handle the properties
for (String property_name : property_names)
{
if (!ConstrainedUtils.persistConstrainedProperty(constrained, property_name, null))
{
continue;
}
if (null == table)
{
field(property_name);
}
else
{
field(table+"."+property_name);
}
}
return this;
}
public Select fields(String... fields)
{
if (null == fields) throw new IllegalArgumentException("fields can't be null.");
if (fields.length > 0)
{
clearGenerated();
mFields.addAll(Arrays.asList(fields));
}
return this;
}
public Select distinct()
{
clearGenerated();
mDistinct = true;
return this;
}
public Select distinctOn(String column)
{
if (null == column) throw new IllegalArgumentException("column can't be null.");
if (0 == column.length()) throw new IllegalArgumentException("column can't be empty.");
clearGenerated();
mDistinct = true;
mDistinctOn.add(column);
return this;
}
public Select distinctOn(String... columns)
{
if (null == columns) throw new IllegalArgumentException("columns can't be null.");
if (columns.length > 0)
{
clearGenerated();
mDistinct = true;
mDistinctOn.addAll(Arrays.asList(columns));
}
return this;
}
public Select from(String from)
{
if (null == from) throw new IllegalArgumentException("from can't be null.");
if (0 == from.length()) throw new IllegalArgumentException("from can't be empty.");
clearGenerated();
mFrom = from;
return this;
}
public Select from(Select query)
{
if (null == query) throw new IllegalArgumentException("query can't be null.");
StringBuilder buffer = new StringBuilder();
buffer.append("(");
buffer.append(query.toString());
buffer.append(")");
from(buffer.toString());
_tableSubselect(query);
return this;
}
public Select from(String alias, Select query)
{
if (null == alias) throw new IllegalArgumentException("alias can't be null.");
if (0 == alias.length()) throw new IllegalArgumentException("alias can't be empty.");
if (null == query) throw new IllegalArgumentException("query can't be null.");
StringBuilder buffer = new StringBuilder();
buffer.append("(");
buffer.append(query.toString());
buffer.append(") ");
buffer.append(alias);
from(buffer.toString());
_tableSubselect(query);
return this;
}
public Select join(String table)
{
if (null == table) throw new IllegalArgumentException("table can't be null.");
if (0 == table.length()) throw new IllegalArgumentException("table can't be empty.");
clearGenerated();
mJoins.add(new JoinDefault(table));
return this;
}
public Select join(String alias, Select query)
{
if (null == alias) throw new IllegalArgumentException("alias can't be null.");
if (0 == alias.length()) throw new IllegalArgumentException("alias can't be empty.");
if (null == query) throw new IllegalArgumentException("query can't be null.");
StringBuilder buffer = new StringBuilder();
buffer.append("(");
buffer.append(query.toString());
buffer.append(") ");
buffer.append(alias);
join(buffer.toString());
tableSubselect(query);
return this;
}
public Select joinCustom(String customJoin)
{
if (null == customJoin) throw new IllegalArgumentException("customJoin can't be null.");
if (0 == customJoin.length()) throw new IllegalArgumentException("customJoin can't be empty.");
clearGenerated();
mJoins.add(new JoinCustom(customJoin));
return this;
}
public Select joinCross(String table)
{
if (null == table) throw new IllegalArgumentException("table can't be null.");
if (0 == table.length()) throw new IllegalArgumentException("table can't be empty.");
clearGenerated();
mJoins.add(new JoinCross(table));
return this;
}
public Select joinInner(String table, JoinCondition condition, String conditionExpression)
{
if (null == table) throw new IllegalArgumentException("table can't be null.");
if (0 == table.length()) throw new IllegalArgumentException("table can't be empty.");
if (null == condition) throw new IllegalArgumentException("condition can't be null.");
if (NATURAL == condition &&
conditionExpression != null) throw new IllegalArgumentException("a NATURAL join condition can't have a join expression.");
if (NATURAL != condition &&
null == conditionExpression) throw new IllegalArgumentException("conditionExpression can't be null.");
if (NATURAL != condition &&
0 == conditionExpression.length()) throw new IllegalArgumentException("conditionExpression can't be empty.");
clearGenerated();
mJoins.add(new JoinInner(table, condition, conditionExpression));
return this;
}
public Select joinOuter(String table, JoinType type, JoinCondition condition, String conditionExpression)
{
if (null == table) throw new IllegalArgumentException("table can't be null.");
if (0 == table.length()) throw new IllegalArgumentException("table can't be empty.");
if (null == type) throw new IllegalArgumentException("type can't be null.");
if (null == condition) throw new IllegalArgumentException("condition can't be null.");
if (NATURAL == condition &&
conditionExpression != null) throw new IllegalArgumentException("a NATURAL join condition can't have a join expression.");
if (NATURAL != condition &&
null == conditionExpression) throw new IllegalArgumentException("conditionExpression can't be null.");
if (NATURAL != condition &&
0 == conditionExpression.length()) throw new IllegalArgumentException("conditionExpression can't be empty.");
clearGenerated();
mJoins.add(new JoinOuter(table, type, condition, conditionExpression));
return this;
}
public Select fieldSubselect(Select query)
{
_fieldSubselect(query);
return this;
}
public Select tableSubselect(Select query)
{
_tableSubselect(query);
return this;
}
public Select groupBy(String groupBy)
{
if (null == groupBy) throw new IllegalArgumentException("groupBy can't be null.");
if (0 == groupBy.length()) throw new IllegalArgumentException("groupBy can't be empty.");
clearGenerated();
mGroupBy.add(groupBy);
return this;
}
public Select groupBy(Class beanClass)
throws DbQueryException
{
return groupByExcluded(beanClass, (String[])null);
}
public Select groupByExcluded(Class beanClass, String... excludedFields)
throws DbQueryException
{
if (null == beanClass) throw new IllegalArgumentException("beanClass can't be null.");
Set<String> property_names = QueryHelper.getBeanPropertyNames(beanClass, excludedFields);
clearGenerated();
for (String property_name : property_names)
{
mGroupBy.add(property_name);
}
return this;
}
public Select having(String having)
{
if (null == having) throw new IllegalArgumentException("having can't be null.");
if (0 == having.length()) throw new IllegalArgumentException("having can't be empty.");
clearGenerated();
mHaving.add(having);
return this;
}
public Select union(String union)
{
if (null == union) throw new IllegalArgumentException("union can't be null.");
if (0 == union.length()) throw new IllegalArgumentException("union can't be empty.");
clearGenerated();
mUnions.add(new Union(union, false));
return this;
}
public Select union(Select union)
throws DbQueryException
{
if (null == union) throw new IllegalArgumentException("union can't be null.");
union(union.getSql());
_unionSubselect(union);
return this;
}
public Select unionAll(String union)
{
if (null == union) throw new IllegalArgumentException("union can't be null.");
if (0 == union.length()) throw new IllegalArgumentException("union can't be empty.");
clearGenerated();
mUnions.add(new Union(union, true));
return this;
}
public Select unionAll(Select union)
throws DbQueryException
{
if (null == union) throw new IllegalArgumentException("union can't be null.");
unionAll(union.getSql());
_unionSubselect(union);
return this;
}
public Select orderBy(String column)
{
clearGenerated();
return orderBy(column, ASC);
}
public Select orderBy(String column, OrderByDirection direction)
{
if (null == column) throw new IllegalArgumentException("column can't be null.");
if (0 == column.length()) throw new IllegalArgumentException("column can't be empty.");
if (null == direction) throw new IllegalArgumentException("direction can't be null.");
OrderBy orderby = new OrderBy(column, direction);
clearGenerated();
mOrderBy.add(orderby);
return this;
}
public Select limit(int limit)
{
if (limit < 1) throw new IllegalArgumentException("limit must be at least 1.");
clearGenerated();
mLimit = limit;
setLimitParameter(null);
return this;
}
public Select limitParameter(String name)
{
if (null == name) throw new IllegalArgumentException("name can't be null.");
if (0 == name.length()) throw new IllegalArgumentException("name can't be empty.");
clearGenerated();
mLimit = -1;
setLimitParameter(name);
return this;
}
public Select offset(int offset)
{
if (offset < 0) throw new IllegalArgumentException("offset must be at least 0.");
clearGenerated();
mOffset = offset;
setOffsetParameter(null);
return this;
}
protected boolean isLimitBeforeOffset()
{
Template template = getTemplate();
if (!template.hasValueId("OFFSET") ||
!template.hasValueId("LIMIT_VALUE")
)
{
return super.isLimitBeforeOffset();
}
String offset = template.getValue("OFFSET");
String limit_value = template.getValue("LIMIT_VALUE");
template.setValue("OFFSET", "offset");
template.setValue("LIMIT_VALUE", "limit");
String limit = template.getBlock("LIMIT");
template.setValue("OFFSET", offset);
template.setValue("LIMIT_VALUE", limit_value);
return limit.indexOf("offset") >= limit.indexOf("limit");
}
public Select offsetParameter(String name)
{
if (null == name) throw new IllegalArgumentException("name can't be null.");
if (0 == name.length()) throw new IllegalArgumentException("name can't be empty.");
clearGenerated();
mOffset = -1;
setOffsetParameter(name);
return this;
}
public Select clone()
{
Select new_instance = super.clone();
if (new_instance != null)
{
if (mFields != null)
{
new_instance.mFields = new ArrayList<String>();
new_instance.mFields.addAll(mFields);
}
if (mJoins != null)
{
new_instance.mJoins = new ArrayList<Join>();
for (Join join : mJoins)
{
new_instance.mJoins.add(join.clone());
}
}
if (mUnions != null)
{
new_instance.mUnions = new ArrayList<Union>();
for (Union union : mUnions)
{
new_instance.mUnions.add(union.clone());
}
}
if (mGroupBy != null)
{
new_instance.mGroupBy = new ArrayList<String>();
new_instance.mGroupBy.addAll(mGroupBy);
}
if (mHaving != null)
{
new_instance.mHaving = new ArrayList<String>();
new_instance.mHaving.addAll(mHaving);
}
if (mDistinctOn != null)
{
new_instance.mDistinctOn = new ArrayList<String>();
new_instance.mDistinctOn.addAll(mDistinctOn);
}
if (mOrderBy != null)
{
new_instance.mOrderBy = new ArrayList<OrderBy>();
for (OrderBy order_by : mOrderBy)
{
new_instance.mOrderBy.add(order_by.clone());
}
}
}
return new_instance;
}
public static class JoinCondition extends EnumClass<String>
{
JoinCondition(String identifier)
{
super(identifier);
}
}
public static class JoinType extends EnumClass<String>
{
JoinType(String identifier)
{
super(identifier);
}
}
public static class OrderByDirection extends EnumClass<String>
{
OrderByDirection(String identifier)
{
super(identifier);
}
public static OrderByDirection getDirection(String identifier)
{
return getMember(OrderByDirection.class, identifier);
}
}
public class JoinCustom extends Join
{
JoinCustom(String customJoin)
{
super(customJoin);
}
String getSql(Template template)
{
return " "+getData();
}
}
public class JoinDefault extends Join implements Cloneable
{
JoinDefault(String table)
{
super(table);
}
String getSql(Template template)
{
assert template != null;
String result = null;
template.setValue("TABLE", getData());
result = template.getBlock("JOIN_DEFAULT");
template.removeValue("TABLE");
assert result != null;
assert result.length() > 0;
return result;
}
public JoinDefault clone()
{
return (JoinDefault)super.clone();
}
}
public class JoinCross extends Join implements Cloneable
{
JoinCross(String table)
{
super(table);
}
String getSql(Template template)
throws DbQueryException
{
assert template != null;
String result = null;
template.setValue("TABLE", getData());
result = template.getBlock("JOIN_CROSS");
if (0 == result.length())
{
throw new UnsupportedSqlFeatureException("CROSS JOIN", mDatasource.getAliasedDriver());
}
template.removeValue("TABLE");
assert result != null;
assert result.length() > 0;
return result;
}
public JoinCross clone()
{
return (JoinCross)super.clone();
}
}
public class JoinInner extends Join implements Cloneable
{
private JoinCondition mCondition = null;
private String mExpression = null;
JoinInner(String table, JoinCondition condition, String expression)
{
super(table);
assert condition != null;
assert condition == Select.NATURAL || (expression != null && expression.length() > 0);
setCondition(condition);
setExpression(expression);
}
String getSql(Template template)
throws DbQueryException
{
assert template != null;
String condition = null;
String result = null;
template.setValue("TABLE", getData());
if (getExpression() != null)
{
template.setValue("EXPRESSION", getExpression());
}
condition = template.getBlock("JOIN_INNER_"+getCondition().toString());
if (0 == condition.length())
{
throw new UnsupportedSqlFeatureException(getCondition().toString()+" for INNER JOIN", mDatasource.getAliasedDriver());
}
template.setValue("JOIN_INNER_"+getCondition().toString(), condition);
result = template.getBlock("JOIN_INNER");
if (0 == result.length())
{
throw new UnsupportedSqlFeatureException("INNER JOIN", mDatasource.getAliasedDriver());
}
template.removeValue("TABLE");
template.removeValue("EXPRESSION");
template.removeValue("JOIN_INNER_"+getCondition().toString());
assert result != null;
assert result.length() > 0;
return result;
}
public JoinCondition getCondition()
{
return mCondition;
}
void setCondition(JoinCondition condition)
{
assert condition != null;
mCondition = condition;
}
public String getExpression()
{
return mExpression;
}
void setExpression(String expression)
{
mExpression = expression;
}
public JoinInner clone()
{
return (JoinInner)super.clone();
}
}
public class JoinOuter extends Join implements Cloneable
{
private JoinType mType = null;
private JoinCondition mCondition = null;
private String mExpression = null;
JoinOuter(String table, JoinType type, JoinCondition condition, String expression)
{
super(table);
assert type != null;
assert condition != null;
assert condition == Select.NATURAL || (expression != null && expression.length() > 0);
setType(type);
setCondition(condition);
setExpression(expression);
}
String getSql(Template template)
throws DbQueryException
{
assert template != null;
String type = null;
String condition = null;
String result = null;
template.setValue("TABLE", getData());
if (getType() != null)
{
type = template.getBlock("JOIN_OUTER_"+getType().toString());
if (0 == type.length())
{
throw new UnsupportedSqlFeatureException(getType().toString()+" for OUTER JOIN", mDatasource.getAliasedDriver());
}
template.setValue("JOIN_OUTER_TYPE", type);
}
if (getExpression() != null)
{
template.setValue("EXPRESSION", getExpression());
}
condition = template.getBlock("JOIN_OUTER_"+getCondition().toString());
if (0 == condition.length())
{
throw new UnsupportedSqlFeatureException(getCondition().toString()+" for OUTER JOIN", mDatasource.getAliasedDriver());
}
template.setValue("JOIN_OUTER_"+getCondition().toString(), condition);
result = template.getBlock("JOIN_OUTER");
if (0 == result.length())
{
throw new UnsupportedSqlFeatureException("OUTER JOIN", mDatasource.getAliasedDriver());
}
template.removeValue("TABLE");
template.removeValue("EXPRESSION");
template.removeValue("JOIN_OUTER_"+getCondition().toString());
template.removeValue("JOIN_OUTER_TYPE");
assert result != null;
assert result.length() > 0;
return result;
}
public JoinType getType()
{
return mType;
}
void setType(JoinType type)
{
assert type != null;
mType = type;
}
public JoinCondition getCondition()
{
return mCondition;
}
void setCondition(JoinCondition condition)
{
assert condition != null;
mCondition = condition;
}
public String getExpression()
{
return mExpression;
}
void setExpression(String expression)
{
mExpression = expression;
}
public JoinOuter clone()
{
return (JoinOuter)super.clone();
}
}
public abstract class Join implements Cloneable
{
private String mData = null;
Join(String data)
{
assert data != null;
assert data.length() > 0;
setData(data);
}
abstract String getSql(Template template) throws DbQueryException;
public String getData()
{
return mData;
}
void setData(String data)
{
assert data != null;
assert data.length() > 0;
mData = data;
}
public Join clone()
{
Join new_instance = null;
try
{
new_instance = (Join)super.clone();
}
catch (CloneNotSupportedException e)
{
new_instance = null;
}
return new_instance;
}
}
public class OrderBy implements Cloneable
{
private String mColumn = null;
private OrderByDirection mDirection = null;
OrderBy(String column, OrderByDirection direction)
{
assert column != null;
assert column.length() > 0;
assert direction != null;
setColumn(column);
setDirection(direction);
}
String getSql(Template template)
{
assert template != null;
String result = null;
template.setValue("COLUMN", getColumn());
template.setValue("DIRECTION", template.getBlock("ORDERBY_"+getDirection().toString()));
result = template.getBlock("ORDERBY_PART");
template.removeValue("COLUMN");
template.removeValue("DIRECTION");
assert result != null;
assert result.length() > 0;
return result;
}
public String getColumn()
{
return mColumn;
}
void setColumn(String column)
{
assert column != null;
assert column.length() > 0;
mColumn = column;
}
public OrderByDirection getDirection()
{
return mDirection;
}
void setDirection(OrderByDirection direction)
{
assert direction != null;
mDirection = direction;
}
public OrderBy clone()
{
OrderBy new_instance = null;
try
{
new_instance = (OrderBy)super.clone();
}
catch (CloneNotSupportedException e)
{
new_instance = null;
}
return new_instance;
}
}
public class Union implements Cloneable
{
private String mExpression = null;
private boolean mAll = false;
Union(String expression, boolean all)
{
setExpression(expression);
setAll(all);
}
void setExpression(String expression)
{
assert expression != null;
assert expression.length() > 0;
mExpression = expression;
}
public String getExpression()
{
return mExpression;
}
void setAll(boolean all)
{
mAll = all;
}
public boolean isAll()
{
return mAll;
}
public Union clone()
{
Union new_instance = null;
try
{
new_instance = (Union)super.clone();
}
catch (CloneNotSupportedException e)
{
new_instance = null;
}
return new_instance;
}
}
}