001: /*
002: * Copyright Aduna (http://www.aduna-software.com/) (c) 2008.
003: *
004: * Licensed under the Aduna BSD-style license.
005: */
006: package org.openrdf.sail.rdbms.algebra;
007:
008: import java.util.ArrayList;
009: import java.util.Collection;
010: import java.util.HashMap;
011: import java.util.HashSet;
012: import java.util.List;
013: import java.util.Map;
014: import java.util.Set;
015:
016: import org.openrdf.query.algebra.QueryModelNode;
017: import org.openrdf.query.algebra.QueryModelVisitor;
018: import org.openrdf.query.algebra.TupleExpr;
019: import org.openrdf.sail.rdbms.algebra.base.FromItem;
020: import org.openrdf.sail.rdbms.algebra.base.RdbmsQueryModelNodeBase;
021: import org.openrdf.sail.rdbms.algebra.base.RdbmsQueryModelVisitorBase;
022: import org.openrdf.sail.rdbms.algebra.base.SqlConstant;
023: import org.openrdf.sail.rdbms.algebra.base.SqlExpr;
024:
025: /**
026: * An SQL query.
027: *
028: * @author James Leigh
029: *
030: */
031: public class SelectQuery extends RdbmsQueryModelNodeBase implements
032: TupleExpr {
033: public static class OrderElem {
034: public final SqlExpr sqlExpr;
035: public final boolean isAscending;
036:
037: protected OrderElem(SqlExpr sqlExpr, boolean isAscending) {
038: this .sqlExpr = sqlExpr;
039: this .isAscending = isAscending;
040: }
041: }
042:
043: private Map<String, SelectProjection> projections = new HashMap();
044: private Map<String, String> bindingNames;
045: private boolean distinct;
046: private FromItem from;
047: private List<OrderElem> order = new ArrayList<OrderElem>();
048: private Integer offset;
049: private Integer limit;
050:
051: public boolean isDistinct() {
052: return distinct;
053: }
054:
055: public void setDistinct(boolean b) {
056: distinct = b;
057: }
058:
059: public boolean isComplex() {
060: if (offset != null || limit != null)
061: return true;
062: return isDistinct() || !order.isEmpty();
063: }
064:
065: public FromItem getFrom() {
066: return from;
067: }
068:
069: public void setFrom(FromItem from) {
070: this .from = from;
071: from.setParentNode(this );
072: }
073:
074: public List<OrderElem> getOrderElems() {
075: return order;
076: }
077:
078: public void addOrder(SqlExpr order, boolean isAscending) {
079: if (order instanceof SqlNull)
080: return;
081: if (order instanceof SqlConstant<?>)
082: return;
083: this .order.add(new OrderElem(order, isAscending));
084: order.setParentNode(this );
085: }
086:
087: public Integer getOffset() {
088: return offset;
089: }
090:
091: public void setOffset(Integer offset) {
092: this .offset = offset;
093: }
094:
095: public Integer getLimit() {
096: return limit;
097: }
098:
099: public void setLimit(Integer limit) {
100: this .limit = limit;
101: }
102:
103: public String getBindingName(ColumnVar var) {
104: if (bindingNames == null)
105: return var.getName();
106: return bindingNames.get(var.getName());
107: }
108:
109: public Set<String> getBindingNames() {
110: if (bindingNames == null) {
111: Set<String> names = new HashSet<String>();
112: for (ColumnVar var : getVars()) {
113: names.add(var.getName());
114: }
115: return names;
116: }
117: return new HashSet<String>(bindingNames.values());
118: }
119:
120: public void setBindingNames(Map<String, String> bindingNames) {
121: this .bindingNames = bindingNames;
122: }
123:
124: public Collection<SelectProjection> getSqlSelectVar() {
125: return projections.values();
126: }
127:
128: public void setSqlSelectVar(Collection<SelectProjection> projections) {
129: this .projections.clear();
130: for (SelectProjection p : projections) {
131: addSqlSelectVar(p);
132: }
133: }
134:
135: public SelectProjection getSelectProjection(String name) {
136: return projections.get(name);
137: }
138:
139: @Override
140: public void replaceChildNode(QueryModelNode current,
141: QueryModelNode replacement) {
142: for (String name : projections.keySet()) {
143: if (projections.get(name) == current) {
144: projections.put(name, (SelectProjection) replacement);
145: replacement.setParentNode(this );
146: return;
147: }
148: }
149: if (from == current) {
150: from = (FromItem) replacement;
151: replacement.setParentNode(this );
152: return;
153: }
154: for (int i = 0, n = order.size(); i < n; i++) {
155: if (order.get(i).sqlExpr == current) {
156: if (replacement instanceof SqlNull
157: || order instanceof SqlConstant<?>) {
158: order.remove(i);
159: return;
160: }
161: boolean asc = order.get(i).isAscending;
162: order.set(i, new OrderElem((SqlExpr) replacement, asc));
163: replacement.setParentNode(this );
164: return;
165: }
166: }
167: super .replaceChildNode(current, replacement);
168: }
169:
170: @Override
171: public <X extends Exception> void visitChildren(
172: QueryModelVisitor<X> visitor) throws X {
173: super .visitChildren(visitor);
174: from.visit(visitor);
175: ArrayList<SelectProjection> list = new ArrayList(projections
176: .values());
177: for (SelectProjection expr : list) {
178: expr.visit(visitor);
179: }
180: for (OrderElem by : new ArrayList<OrderElem>(order)) {
181: by.sqlExpr.visit(visitor);
182: }
183: }
184:
185: @Override
186: public SelectQuery clone() {
187: SelectQuery clone = (SelectQuery) super .clone();
188: clone.distinct = distinct;
189: clone.projections = new HashMap<String, SelectProjection>();
190: for (SelectProjection expr : projections.values()) {
191: clone.addSqlSelectVar(expr.clone());
192: }
193: clone.from = from.clone();
194: clone.order = new ArrayList<OrderElem>(order);
195: return clone;
196: }
197:
198: @Override
199: public <X extends Exception> void visit(
200: RdbmsQueryModelVisitorBase<X> visitor) throws X {
201: visitor.meet(this );
202: }
203:
204: public boolean hasSqlSelectVar(SelectProjection node) {
205: return projections.containsKey(node.getVar().getName());
206: }
207:
208: public void addSqlSelectVar(SelectProjection node) {
209: projections.put(node.getVar().getName(), node);
210: node.setParentNode(this );
211: }
212:
213: public Collection<ColumnVar> getProjections() {
214: List<ColumnVar> vars = new ArrayList<ColumnVar>();
215: for (SelectProjection proj : projections.values()) {
216: ColumnVar var = proj.getVar();
217: if (bindingNames != null) {
218: var = var.as(bindingNames.get(var.getName()));
219: }
220: vars.add(var);
221: }
222: return vars;
223: }
224:
225: public Collection<ColumnVar> getVars() {
226: List<ColumnVar> vars = new ArrayList<ColumnVar>();
227: from.appendVars(vars);
228: return vars;
229: }
230:
231: public ColumnVar getVar(String varName) {
232: return from.getVar(varName);
233: }
234:
235: public void addFilter(SqlExpr sql) {
236: from.addFilter(sql);
237: }
238:
239: public void addJoin(SelectQuery right) {
240: from.addJoin(right.getFrom());
241: }
242:
243: public void addLeftJoin(SelectQuery right) {
244: FromItem join = right.getFrom();
245: join.setLeft(true);
246: from.addJoin(join);
247: }
248:
249: public FromItem getFromItem(String alias) {
250: return from.getFromItem(alias);
251: }
252:
253: public List<SqlExpr> getFilters() {
254: return from.getFilters();
255: }
256:
257: public void removeFilter(SqlExpr sqlExpr) {
258: from.removeFilter(sqlExpr);
259: }
260:
261: public Map<String, ColumnVar> getVarMap() {
262: Collection<ColumnVar> vars = getVars();
263: Map<String, ColumnVar> map = new HashMap<String, ColumnVar>(
264: vars.size());
265: for (ColumnVar var : vars) {
266: if (!map.containsKey(var.getName())) {
267: map.put(var.getName(), var);
268: }
269: }
270: return map;
271: }
272:
273: }
|