001: /*
002: * Copyright 2003 (C) TJDO.
003: * All rights reserved.
004: *
005: * This software is distributed under the terms of the TJDO License version 1.0.
006: * See the terms of the TJDO License in the documentation provided with this software.
007: *
008: * $Id: SetLiteral.java,v 1.2 2004/01/25 22:31:27 jackknifebarber Exp $
009: */
010:
011: package com.triactive.jdo.store;
012:
013: import javax.jdo.JDOUserException;
014: import java.util.Iterator;
015: import java.util.Set;
016:
017: /**
018: * A SetLiteral is a SQL expression that will test if a column of table
019: * falls within the given Set of values. This is used for <code>Query</code>s
020: * where a transient Set is passed in as a parameter.
021: *
022: * @author <a href="mailto:pierreg0@users.sourceforge.net">Kelly Grizzle</a>
023: * @version $Revision: 1.2 $
024: */
025:
026: class SetLiteral extends SetExpression {
027: private final Set value;
028: private final boolean isEmpty;
029: private final boolean containsNull;
030: private final DatabaseAdapter dba;
031:
032: /**
033: * Construct a SetLiteral.
034: *
035: * @param qs The QueryStatement the SetLiteral will be used in.
036: * @param value The transient Set that is the value of the SetLiteral.
037: */
038:
039: public SetLiteral(QueryStatement qs, Set value) {
040: super (qs);
041:
042: this .value = value;
043:
044: containsNull = (null != value) && value.contains(null);
045: dba = qs.getStoreManager().getDatabaseAdapter();
046:
047: /*
048: * We'll consider the Set to be empty if it is null, is truly empty,
049: * or only contains null. If it contains null we need a special case
050: * when creating the SQL.
051: */
052: isEmpty = (null == value) || (value.isEmpty())
053: || (1 == value.size() && containsNull);
054:
055: /*
056: * If the Set is empty, don't build the list of SQLExpressions.
057: */
058: if (!isEmpty) {
059: st.append("(");
060:
061: boolean hadPrev = false;
062:
063: for (Iterator it = value.iterator(); it.hasNext();) {
064: Object current = it.next();
065:
066: if (null != current) {
067: Mapping m = dba.getMapping(current.getClass());
068: SQLExpression expr = m.newSQLLiteral(qs, current);
069:
070: /*
071: * Append the SQLExpression (should be a literal) for the current element.
072: */
073: st.append(hadPrev ? "," : "");
074: st.append(expr);
075:
076: hadPrev = true;
077: }
078: }
079:
080: st.append(")");
081: }
082: }
083:
084: /**
085: * Return the BooleanExpression that results from SetLiteral.contains(SQLExpression).
086: *
087: * @param expr The SQLExpression that is checked for membership in the Set.
088: *
089: * @return The BooleanExpression that results from SetLiteral.contains(SQLExpression).
090: */
091: public BooleanExpression containsMethod(SQLExpression expr) {
092: BooleanExpression returnVal = isEmpty ? new BooleanLiteral(qs,
093: false) : expr.in(this );
094:
095: /*
096: * The expression FIELD IN ('Foo','Bar',NULL) does not work as we need it to.
097: * To get around this, if there is a null in the Set parameter, we will explicitly
098: * check if expr is NULL.
099: */
100: if (containsNull)
101: returnVal = returnVal.ior(expr.eq(new NullLiteral(qs)));
102:
103: return returnVal;
104: }
105:
106: public BooleanExpression isEmptyMethod() {
107: return new BooleanLiteral(qs, isEmpty);
108: }
109: }
|