/* * Copyright 2004-2013 H2 Group. Multiple-Licensed under the H2 License, * Version 1.0, and under the Eclipse Public License, Version 1.0 * (http://h2database.com/html/license.html). * Initial Developer: H2 Group * * Nicolas Fortin, Atelier SIG, IRSTV FR CNRS 24888 * Support for the operator "&&" as an alias for SPATIAL_INTERSECTS */ package com.redspr.redquerybuilder.core.client.command.dml; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Set; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.VerticalPanel; import com.redspr.redquerybuilder.core.client.BaseSqlWidget; import com.redspr.redquerybuilder.core.client.Visitor; import com.redspr.redquerybuilder.core.client.VisitorBase; import com.redspr.redquerybuilder.core.client.engine.ColumnResolver; import com.redspr.redquerybuilder.core.client.engine.Session; import com.redspr.redquerybuilder.core.client.engine.TableEvent; import com.redspr.redquerybuilder.core.client.expression.Comparison; import com.redspr.redquerybuilder.core.client.expression.ConditionAndOr; import com.redspr.redquerybuilder.core.client.expression.Expression; import com.redspr.redquerybuilder.core.client.expression.ExpressionColumn; import com.redspr.redquerybuilder.core.client.table.TableFilter; import com.redspr.redquerybuilder.core.client.util.CommandListBox; import com.redspr.redquerybuilder.core.client.util.CommandWithLabel; import com.redspr.redquerybuilder.core.client.util.ObjectArray; import com.redspr.redquerybuilder.core.client.util.StatementBuilder; import com.redspr.redquerybuilder.core.client.util.XWidget; import com.redspr.redquerybuilder.core.shared.meta.Column; import com.redspr.redquerybuilder.core.shared.meta.Table; public class Select extends Query implements ColumnResolver { private final Button add = new Button("Add condition"); private final XWidget<Expression> xcondition = new XWidget<Expression>(); private HashMap<Expression, Object> currentGroup; private int currentGroupRowId; private ObjectArray<Expression> expressions; private final ObjectArray<TableFilter> filters = ObjectArray.newInstance(); // private ObjectArray<SelectOrderBy> orderList; private ObjectArray<Expression> group; private boolean[] groupByExpression; private int[] groupIndex; private Expression having; private boolean isQuickAggregateQuery; private final Session session; private int visibleColumnCount; private final VerticalPanel vp = new VerticalPanel(); private final CommandListBox what; public Select(final Session session2) { super(session2); session = session2; session.setSelect(this); initWidget(vp); what = new CommandListBox(this); what.addStyleName("rqbWhat"); // XXX to be removed what.addStyleName("rqbFrom"); what.setVisible(session.getConfig().getFrom().isVisible()); vp.add(what); vp.add(add); add.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { addFirstCondition(); fireDirty(); } }); List items = new ArrayList(); CommandWithLabel prompt = new PromptCommand(); what.setValue(prompt); items.add(prompt); // XXX 00 What is SQL 92 case sensitivity rule for (Table t : session.getDatabase().getMainSchema().getTables()) { if (!t.isHidden()) { items.add(new TableCommand(t)); } } what.setAcceptableValues(items); vp.add(xcondition); } // XXX scope for testing public Comparison addFirstCondition() { Comparison c = new Comparison(session); addCondition(c); return c; } class TableCommand extends CommandWithLabel { private final Table table; TableCommand(Table t) { super(t); table = t; } @Override public void execute() { updateTable(table); } } class PromptCommand extends CommandWithLabel { PromptCommand() { super("Please select"); } @Override public void execute() { updateTable(null); } } /** * Add a condition to the list of conditions. * * @param cond * the condition to add */ public void addCondition(Expression cond) { Expression condition = getCondition(); if (condition == null) { condition = cond; } else { condition = new ConditionAndOr(session, ConditionAndOr.AND, cond, condition); } setCondition(condition); } private void setCondition(Expression condition) { xcondition.setValue(condition); } /** * Add a table to the query. * * @param filter * the table to add * @param isTop * if the table can be the first table in the query plan */ public void addTableFilter(TableFilter filter, boolean isTop) { // Oracle doesn't check on duplicate aliases // String alias = filter.getAlias(); // if(filterNames.contains(alias)) { // throw Message.getSQLException( // ErrorCode.DUPLICATE_TABLE_ALIAS, alias); // } // filterNames.add(alias); filters.add(filter); } public int getColumnCount() { return visibleColumnCount; } public Expression getCondition() { return xcondition.getValue(); } public HashMap<Expression, Object> getCurrentGroup() { return currentGroup; } public int getCurrentGroupRowId() { return currentGroupRowId; } public ObjectArray<Expression> getExpressions() { return expressions; } public ObjectArray<TableFilter> getFilters() { return filters; } public String getSQL(List args) { StatementBuilder buff = new StatementBuilder("SELECT "); // if (distinct) { // buff.append("DISTINCT "); // } if (expressions != null) { for (int i = 0; i < expressions.size(); i++) { buff.appendExceptFirst(", "); buff.append(expressions.get(i).getSQL(args)); } } buff.append("\nFROM "); TableFilter filter = null; if (filters.size() > 0) { filter = filters.get(0); } if (filter != null) { buff.resetCount(); int i = 0; do { buff.appendExceptFirst("\n"); buff.append(filter.getSQL(i++ > 0, args)); filter = filter.getJoin(); } while (filter != null); } else { buff.resetCount(); int i = 0; for (TableFilter f : filters) { buff.appendExceptFirst("\n"); buff.append(f.getSQL(i++ > 0, args)); } } if (xcondition.getValue() != null) { buff.append("\nWHERE ").append(xcondition.getValue().getSQL(args)); } // if (groupIndex != null) { // buff.append("\nGROUP BY "); // buff.resetCount(); // for (int gi : groupIndex) { // Expression g = exprList[gi]; // g = g.getNonAliasExpression(); // buff.appendExceptFirst(", "); // buff.append(StringUtils.unEnclose(g.getSQL())); // } // } // if (group != null) { // buff.append("\nGROUP BY "); // buff.resetCount(); // for (Expression g : group) { // buff.appendExceptFirst(", "); // buff.append(StringUtils.unEnclose(g.getSQL())); // } // } // if (having != null) { // // could be set in addGlobalCondition // // in this case the query is not run directly, just getPlanSQL is // // called // Expression h = having; // buff.append("\nHAVING ").append(StringUtils.unEnclose(h.getSQL())); // } else if (havingIndex >= 0) { // Expression h = exprList[havingIndex]; // buff.append("\nHAVING ").append(StringUtils.unEnclose(h.getSQL())); // } // if (sort != null) { // buff.append("\nORDER BY ").append(sort.getSQL(exprList, // visibleColumnCount)); // } // if (orderList != null) { // buff.append("\nORDER BY "); // buff.resetCount(); // for (SelectOrderBy o : orderList) { // buff.appendExceptFirst(", "); // buff.append(StringUtils.unEnclose(o.getSQL())); // } // } // if (limitExpr != null) { // buff.append("\nLIMIT ").append(StringUtils.unEnclose(limitExpr.getSQL())); // if (offsetExpr != null) { // buff.append(" OFFSET ").append(StringUtils.unEnclose(offsetExpr.getSQL())); // } // } // if (isForUpdate) { // buff.append("\nFOR UPDATE"); // } // if (isQuickAggregateQuery) { // buff.append("\n/* direct lookup */"); // } // if (isDistinctQuery) { // buff.append("\n/* distinct */"); // } // if (sortUsingIndex) { // buff.append("\n/* index sorted */"); // } // if (isGroupQuery) { // if (isGroupSortedQuery) { // buff.append("\n/* group sorted */"); // } // } return buff.toString(); } // public ListBox getWhat() { // return what; // } // public HashSet<Table> getTables() { // HashSet<Table> set = New.hashSet(); // for (TableFilter filter : filters) { // set.add(filter.getTable()); // } // return set; // } /** * Check if this is an aggregate query with direct lookup, for example a * query of the type SELECT COUNT(*) FROM TEST or SELECT MAX(ID) FROM TEST. * * @return true if a direct lookup is possible */ public boolean isQuickAggregateQuery() { return isQuickAggregateQuery; } @Override public BaseSqlWidget remove(Expression e) { if (getCondition() == e) { setCondition(null); return this; } throw new IllegalArgumentException(); } @Override public void replace(Expression e0, Expression e1) { if (getCondition() == e0) { setCondition(e1); } } public void setExpressions(ObjectArray<Expression> p) { this.expressions = p; } // public void mapColumns(ColumnResolver resolver, int level) throws // SQLException { // for (Expression e : expressions) { // e.mapColumns(resolver, level); // } // if (condition != null) { // condition.mapColumns(resolver, level); // } // } // // public void setEvaluatable(TableFilter tableFilter, boolean b) { // for (Expression e : expressions) { // e.setEvaluatable(tableFilter, b); // } // if (condition != null) { // condition.setEvaluatable(tableFilter, b); // } // } public void setGroupBy(ObjectArray<Expression> p) { this.group = p; } public void setHaving(Expression p) { this.having = p; } public void updateTable(Table tt) { if (tt == null) { filters.clear(); } else if (getFilters().size() == 0) { TableFilter filter = new TableFilter(session, tt, TableFilter .newAlias(), Select.this); addTableFilter(filter, true); // XXX really is true? } else { getFilters().get(0).setTable(tt); } expressions = null; // XXX 03 bit harsh? setCondition(null); session.getMsgBus().fireEvent(new TableEvent()); } @Override public void onDirty() { garbageCollectFilters(); add.setVisible(getCondition() == null && this.getFilters().size() > 0); if (getFilters().size() > 0) { what.setValue(new TableCommand(getFilters().get(0).getTable())); } } public void garbageCollectFilters() { if (filters.size() > 1) { // XXX identity? final Set<TableFilter> used = new HashSet<TableFilter>(); used.add(null); Visitor counter = new VisitorBase() { @Override public void handle(BaseSqlWidget w) { if (w instanceof ExpressionColumn) { ExpressionColumn ec = (ExpressionColumn) w; TableFilter tf = ec.getTableFilter(); if (used.add(tf)) { if (tf.getJoinCondition() != null) { tf.getJoinCondition().traverse(this); } } } } }; if (getCondition() != null) { getCondition().traverse(counter); } boolean removed; do { removed = false; TableFilter prev = filters.get(0); TableFilter x = prev.getJoin(); while (x != null) { if (!used.contains(x)) { // look for used in all other filters? int i = filters.indexOf(x); if (i > 0) { filters.remove(i); } // XXX why is this the case? // just when comma seperated? prev.setJoin(x.getJoin()); removed = true; } prev = x; x = x.getJoin(); } } while (removed); } } @Override public void acceptChildren(Visitor callback) { Expression condition = getCondition(); if (condition != null) { condition.traverse(callback); } } @Override public Column resolveColumn(String alias, String columnName) { for (TableFilter tf : getFilters()) { if (alias == null || alias.equals(tf.getAlias())) { Column c = tf.getTable().getColumn(columnName); if (c != null) { return c; } // XXX if alias != null should blowup? // XXX should blowup if find more than one? } //if (alias.equals(tf.getAlias())) { // return tf.getTable().getColumn(columnName); //} } // XXX log? Window.alert("Unable to find " + alias + "." + columnName); return null; } public TableFilter getTableFilter(String alias) { if (alias == null) { return getFilters().get(0); } for (TableFilter tf : getFilters()) { if (alias.equals(tf.getAlias())) { return tf; } } return null; } // public void addGlobalCondition(Parameter param, int columnId, int // comparisonType) throws SQLException { // addParameter(param); // Expression col = expressions.get(columnId); // col = col.getNonAliasExpression(); // Expression comp = new Comparison(session, comparisonType, col, param); // comp = comp.optimize(session); // boolean addToCondition = true; // if (isGroupQuery) { // addToCondition = false; // for (int i = 0; groupIndex != null && i < groupIndex.length; i++) { // if (groupIndex[i] == columnId) { // addToCondition = true; // break; // } // } // if (!addToCondition) { // if (havingIndex >= 0) { // having = expressions.get(havingIndex); // } // if (having == null) { // having = comp; // } else { // having = new ConditionAndOr(ConditionAndOr.AND, having, comp); // } // } // } // if (addToCondition) { // if (condition == null) { // condition = comp; // } else { // condition = new ConditionAndOr(ConditionAndOr.AND, condition, comp); // } // } // } // public String getFirstColumnAlias(Session s) { // if (SysProperties.CHECK) { // if (visibleColumnCount > 1) { // Message.throwInternalError("" + visibleColumnCount); // } // } // Expression expr = expressions.get(0); // if (expr instanceof Alias) { // return expr.getAlias(); // } // Mode mode = s.getDatabase().getMode(); // String name = s.getNextSystemIdentifier(getSQL()); // expr = new Alias(expr, name, mode.aliasColumnName); // expressions.set(0, expr); // return expr.getAlias(); // } // }