/* * Copyright (c) 1998-2011 Caucho Technology -- all rights reserved * * This file is part of Resin(R) Open Source * * Each copy or derived work must preserve the copyright notice and this * notice unmodified. * * Resin Open Source is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * Resin Open Source is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty * of NON-INFRINGEMENT. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with Resin Open Source; if not, write to the * Free Software Foundation, Inc. * 59 Temple Place, Suite 330 * Boston, MA 02111-1307 USA * * @author Scott Ferguson */ package com.caucho.amber.expr; import com.caucho.amber.query.FromItem; import com.caucho.amber.query.QueryParser; import com.caucho.amber.table.AmberColumn; import com.caucho.amber.table.ForeignColumn; import com.caucho.amber.table.LinkColumns; import com.caucho.amber.table.AmberTable; import com.caucho.util.CharBuffer; import java.util.ArrayList; /** * Represents a member query expression */ public class MemberExpr extends AbstractAmberExpr { private boolean _isNot; // PathExpr or ArgExpr (jpa/10c8) private AmberExpr _itemExpr; private AmberExpr _collectionExpr; private MemberExpr(AmberExpr itemExpr, AmberExpr collectionExpr, boolean isNot) { _itemExpr = itemExpr; _collectionExpr = collectionExpr; _isNot = isNot; } public static AmberExpr create(QueryParser parser, AmberExpr itemExpr, AmberExpr collectionExpr, boolean isNot) { if (collectionExpr instanceof IdExpr) collectionExpr = ((CollectionIdExpr) collectionExpr).getPath(); if (itemExpr instanceof ArgExpr) { // jpa/10c8, jpa/10c9 } else if (itemExpr instanceof ManyToOneExpr) { // jpa/10ca } else if (collectionExpr instanceof OneToManyExpr) { // ejb/06u0, jpa/10c4, jpa/10c5 OneToManyExpr oneToMany = (OneToManyExpr) collectionExpr; PathExpr parent = oneToMany.getParent(); FromItem childFromItem = ((PathExpr) itemExpr).getChildFromItem(); AmberExpr expr; expr = new ManyToOneJoinExpr(oneToMany.getLinkColumns(), childFromItem, parent.getChildFromItem()); if (isNot) return new UnaryExpr(QueryParser.NOT, expr); else return expr; } return new MemberExpr(itemExpr, collectionExpr, isNot); } /** * Binds the expression as a select item. */ public AmberExpr bindSelect(QueryParser parser) { return this; } /** * Returns true for a boolean expression. */ public boolean isBoolean() { return true; } /** * Returns true if the expression uses the from item. */ public boolean usesFrom(FromItem from, int type, boolean isNot) { if (! (_itemExpr instanceof PathExpr)) return false; return (_collectionExpr.usesFrom(from, type) || ((PathExpr) _itemExpr).usesFrom(from, type)); } /** * Returns true if the expression uses the from item. */ public AmberExpr replaceJoin(JoinExpr join) { if (_itemExpr instanceof PathExpr) { _collectionExpr = _collectionExpr.replaceJoin(join); _itemExpr = (PathExpr) _itemExpr.replaceJoin(join); } return this; } /** * Generates the where expression. */ public void generateWhere(CharBuffer cb) { generateInternalWhere(cb, true); } /** * Generates the (update) where expression. */ public void generateUpdateWhere(CharBuffer cb) { generateInternalWhere(cb, false); } /** * Generates the having expression. */ public void generateHaving(CharBuffer cb) { generateWhere(cb); } // // private private void generateInternalWhere(CharBuffer cb, boolean select) { OneToManyExpr oneToMany = null; // ManyToMany is implemented as a // ManyToOne[embeddeding OneToMany] if (_collectionExpr instanceof ManyToOneExpr) { PathExpr expr = ((ManyToOneExpr) _collectionExpr).getParent(); if (expr instanceof OneToManyExpr) oneToMany = (OneToManyExpr) expr; } else if (_collectionExpr instanceof OneToManyExpr) { oneToMany = (OneToManyExpr) _collectionExpr; } else throw new UnsupportedOperationException(); LinkColumns join = oneToMany.getLinkColumns(); if (_isNot) cb.append("NOT "); // jpa/10ca // XXX: needs to handle compound PK. ForeignColumn fk = (ForeignColumn) join.getColumns().get(0); cb.append(oneToMany.getParent().getChildFromItem().getName()); cb.append('.'); cb.append(fk.getTargetColumn().getName()); // changed to IN for jpa/10ca cb.append("EXISTS (SELECT *"); cb.append(" IN (SELECT "); // SELECT *"); cb.append(fk.getName()); AmberTable table = join.getSourceTable(); cb.append(" FROM " + table.getName() + " caucho"); cb.append(" WHERE "); String targetTable = oneToMany.getParent().getChildFromItem().getName(); cb.append(join.generateJoin("caucho", targetTable)); if (_itemExpr instanceof ArgExpr) { cb.append(" AND caucho."); if (_collectionExpr instanceof ManyToOneExpr) { join = ((ManyToOneExpr) _collectionExpr).getLinkColumns(); String name = join.getColumns().get(0).getName(); cb.append(name); } else { // XXX: needs to handle compound PK. ArrayList<AmberColumn> idColumns = join.getSourceTable().getIdColumns(); cb.append(idColumns.get(0).getName()); } cb.append(" = ?"); } else if (_collectionExpr instanceof ManyToOneExpr) { join = ((ManyToOneExpr) _collectionExpr).getLinkColumns(); String itemWhere; boolean isArg = false; String where; if (_itemExpr instanceof ManyToOneExpr) { LinkColumns manyToOneJoin = ((ManyToOneExpr) _itemExpr).getLinkColumns(); itemWhere = ((ManyToOneExpr) _itemExpr).getParent().getChildFromItem().getName(); where = join.generateJoin(manyToOneJoin, "caucho", itemWhere); } else { if (_itemExpr instanceof PathExpr) { itemWhere = ((PathExpr) _itemExpr).getChildFromItem().getName(); } else { isArg = true; itemWhere = "?"; } where = join.generateJoin("caucho", itemWhere, isArg); } cb.append(" AND " + where); } else if (_collectionExpr instanceof OneToManyExpr) { if (_itemExpr instanceof ManyToOneExpr) { join = ((ManyToOneExpr) _itemExpr).getLinkColumns(); String itemWhere = ((ManyToOneExpr) _itemExpr).getParent().getChildFromItem().getName(); String where = join.generateJoin(itemWhere, "caucho"); cb.append(" AND " + where); } else { // XXX: needs to handle compound PK. ArrayList<AmberColumn> idColumns = join.getSourceTable().getIdColumns(); String id = idColumns.get(0).getName(); cb.append(" AND (caucho." + id + " = "); FromItem childFromItem = ((PathExpr) _itemExpr).getChildFromItem(); if (childFromItem != null) { cb.append(childFromItem.getName() + "."); // XXX: needs to handle compound PK. idColumns = childFromItem.getTable().getIdColumns(); cb.append(idColumns.get(0).getName() + ")"); } } } cb.append(')'); } }