001: /*
002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: * Free Software Foundation, Inc.
023: * 59 Temple Place, Suite 330
024: * Boston, MA 02111-1307 USA
025: *
026: * @author Scott Ferguson
027: */
028:
029: package com.caucho.amber.expr;
030:
031: import com.caucho.amber.query.FromItem;
032: import com.caucho.amber.query.QueryParser;
033: import com.caucho.amber.table.Column;
034: import com.caucho.amber.table.ForeignColumn;
035: import com.caucho.amber.table.LinkColumns;
036: import com.caucho.amber.table.Table;
037: import com.caucho.util.CharBuffer;
038:
039: import java.util.ArrayList;
040:
041: /**
042: * Represents a member query expression
043: */
044: public class MemberExpr extends AbstractAmberExpr {
045: private boolean _isNot;
046:
047: // PathExpr or ArgExpr (jpa/10c8)
048: private AmberExpr _itemExpr;
049:
050: private AmberExpr _collectionExpr;
051:
052: private MemberExpr(AmberExpr itemExpr, AmberExpr collectionExpr,
053: boolean isNot) {
054: _itemExpr = itemExpr;
055: _collectionExpr = collectionExpr;
056: _isNot = isNot;
057: }
058:
059: public static AmberExpr create(QueryParser parser,
060: AmberExpr itemExpr, AmberExpr collectionExpr, boolean isNot) {
061: if (collectionExpr instanceof IdExpr)
062: collectionExpr = ((CollectionIdExpr) collectionExpr)
063: .getPath();
064:
065: if (itemExpr instanceof ArgExpr) {
066: // jpa/10c8, jpa/10c9
067: } else if (itemExpr instanceof ManyToOneExpr) {
068: // jpa/10ca
069: } else if (collectionExpr instanceof OneToManyExpr) {
070: // ejb/06u0, jpa/10c4, jpa/10c5
071: OneToManyExpr oneToMany = (OneToManyExpr) collectionExpr;
072: PathExpr parent = oneToMany.getParent();
073:
074: FromItem childFromItem = ((PathExpr) itemExpr)
075: .getChildFromItem();
076:
077: AmberExpr expr;
078:
079: expr = new ManyToOneJoinExpr(oneToMany.getLinkColumns(),
080: childFromItem, parent.getChildFromItem());
081:
082: if (isNot)
083: return new UnaryExpr(QueryParser.NOT, expr);
084: else
085: return expr;
086: }
087:
088: return new MemberExpr(itemExpr, collectionExpr, isNot);
089: }
090:
091: /**
092: * Binds the expression as a select item.
093: */
094: public AmberExpr bindSelect(QueryParser parser) {
095: return this ;
096: }
097:
098: /**
099: * Returns true for a boolean expression.
100: */
101: public boolean isBoolean() {
102: return true;
103: }
104:
105: /**
106: * Returns true if the expression uses the from item.
107: */
108: public boolean usesFrom(FromItem from, int type, boolean isNot) {
109: if (!(_itemExpr instanceof PathExpr))
110: return false;
111:
112: return (_collectionExpr.usesFrom(from, type) || ((PathExpr) _itemExpr)
113: .usesFrom(from, type));
114: }
115:
116: /**
117: * Returns true if the expression uses the from item.
118: */
119: public AmberExpr replaceJoin(JoinExpr join) {
120: if (_itemExpr instanceof PathExpr) {
121: _collectionExpr = _collectionExpr.replaceJoin(join);
122: _itemExpr = (PathExpr) _itemExpr.replaceJoin(join);
123: }
124:
125: return this ;
126: }
127:
128: /**
129: * Generates the where expression.
130: */
131: public void generateWhere(CharBuffer cb) {
132: generateInternalWhere(cb, true);
133: }
134:
135: /**
136: * Generates the (update) where expression.
137: */
138: public void generateUpdateWhere(CharBuffer cb) {
139: generateInternalWhere(cb, false);
140: }
141:
142: /**
143: * Generates the having expression.
144: */
145: public void generateHaving(CharBuffer cb) {
146: generateWhere(cb);
147: }
148:
149: //
150: // private
151:
152: private void generateInternalWhere(CharBuffer cb, boolean select) {
153: OneToManyExpr oneToMany = null;
154:
155: // ManyToMany is implemented as a
156: // ManyToOne[embeddeding OneToMany]
157: if (_collectionExpr instanceof ManyToOneExpr) {
158: PathExpr expr = ((ManyToOneExpr) _collectionExpr)
159: .getParent();
160: if (expr instanceof OneToManyExpr)
161: oneToMany = (OneToManyExpr) expr;
162:
163: } else if (_collectionExpr instanceof OneToManyExpr) {
164: oneToMany = (OneToManyExpr) _collectionExpr;
165: } else
166: throw new UnsupportedOperationException();
167:
168: LinkColumns join = oneToMany.getLinkColumns();
169:
170: if (_isNot)
171: cb.append("NOT ");
172:
173: // jpa/10ca
174: // XXX: needs to handle compound PK.
175: ForeignColumn fk = (ForeignColumn) join.getColumns().get(0);
176: cb.append(oneToMany.getParent().getChildFromItem().getName());
177: cb.append('.');
178: cb.append(fk.getTargetColumn().getName());
179:
180: // changed to IN for jpa/10ca cb.append("EXISTS (SELECT *");
181: cb.append(" IN (SELECT "); // SELECT *");
182: cb.append(fk.getName());
183: Table table = join.getSourceTable();
184: cb.append(" FROM " + table.getName() + " caucho");
185: cb.append(" WHERE ");
186:
187: String targetTable = oneToMany.getParent().getChildFromItem()
188: .getName();
189:
190: cb.append(join.generateJoin("caucho", targetTable));
191:
192: if (_itemExpr instanceof ArgExpr) {
193:
194: cb.append(" AND caucho.");
195:
196: if (_collectionExpr instanceof ManyToOneExpr) {
197: join = ((ManyToOneExpr) _collectionExpr)
198: .getLinkColumns();
199:
200: String name = join.getColumns().get(0).getName();
201:
202: cb.append(name);
203: } else {
204: // XXX: needs to handle compound PK.
205: ArrayList<Column> idColumns = join.getSourceTable()
206: .getIdColumns();
207:
208: cb.append(idColumns.get(0).getName());
209: }
210:
211: cb.append(" = ?");
212: } else if (_collectionExpr instanceof ManyToOneExpr) {
213: join = ((ManyToOneExpr) _collectionExpr).getLinkColumns();
214:
215: String itemWhere;
216: boolean isArg = false;
217:
218: String where;
219:
220: if (_itemExpr instanceof ManyToOneExpr) {
221: LinkColumns manyToOneJoin = ((ManyToOneExpr) _itemExpr)
222: .getLinkColumns();
223:
224: itemWhere = ((ManyToOneExpr) _itemExpr).getParent()
225: .getChildFromItem().getName();
226:
227: where = join.generateJoin(manyToOneJoin, "caucho",
228: itemWhere);
229: } else {
230: if (_itemExpr instanceof PathExpr) {
231: itemWhere = ((PathExpr) _itemExpr)
232: .getChildFromItem().getName();
233: } else {
234: isArg = true;
235: itemWhere = "?";
236: }
237:
238: where = join.generateJoin("caucho", itemWhere, isArg);
239: }
240:
241: cb.append(" AND " + where);
242: } else if (_collectionExpr instanceof OneToManyExpr) {
243: if (_itemExpr instanceof ManyToOneExpr) {
244:
245: join = ((ManyToOneExpr) _itemExpr).getLinkColumns();
246:
247: String itemWhere = ((ManyToOneExpr) _itemExpr)
248: .getParent().getChildFromItem().getName();
249:
250: String where = join.generateJoin(itemWhere, "caucho");
251:
252: cb.append(" AND " + where);
253: } else {
254: // XXX: needs to handle compound PK.
255: ArrayList<Column> idColumns = join.getSourceTable()
256: .getIdColumns();
257:
258: String id = idColumns.get(0).getName();
259:
260: cb.append(" AND (caucho." + id + " = ");
261:
262: FromItem childFromItem = ((PathExpr) _itemExpr)
263: .getChildFromItem();
264:
265: if (childFromItem != null) {
266: cb.append(childFromItem.getName() + ".");
267:
268: // XXX: needs to handle compound PK.
269: idColumns = childFromItem.getTable().getIdColumns();
270:
271: cb.append(idColumns.get(0).getName() + ")");
272: }
273: }
274: }
275:
276: cb.append(')');
277: }
278: }
|