001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: */
019: package org.apache.openjpa.jdbc.kernel.exps;
020:
021: import java.util.Map;
022:
023: import org.apache.openjpa.jdbc.meta.ClassMapping;
024: import org.apache.openjpa.jdbc.meta.FieldMapping;
025: import org.apache.openjpa.jdbc.schema.Column;
026: import org.apache.openjpa.jdbc.schema.Table;
027: import org.apache.openjpa.jdbc.sql.DBDictionary;
028: import org.apache.openjpa.jdbc.sql.SQLBuffer;
029: import org.apache.openjpa.jdbc.sql.Select;
030: import org.apache.openjpa.kernel.exps.ExpressionVisitor;
031: import org.apache.openjpa.meta.XMLMetaData;
032: import serp.util.Numbers;
033:
034: /**
035: * Test if one string starts with another.
036: *
037: * @author Abe White
038: */
039: class StartsWithExpression implements Exp {
040:
041: private final Val _val1;
042: private final Val _val2;
043:
044: /**
045: * Constructor. Supply values.
046: */
047: public StartsWithExpression(Val val1, Val val2) {
048: _val1 = val1;
049: _val2 = val2;
050: }
051:
052: public ExpState initialize(Select sel, ExpContext ctx, Map contains) {
053: ExpState s1 = _val1.initialize(sel, ctx, 0);
054: ExpState s2 = _val2.initialize(sel, ctx, 0);
055: return new BinaryOpExpState(sel.and(s1.joins, s2.joins), s1, s2);
056: }
057:
058: public void appendTo(Select sel, ExpContext ctx, ExpState state,
059: SQLBuffer buf) {
060: BinaryOpExpState bstate = (BinaryOpExpState) state;
061: _val1.calculateValue(sel, ctx, bstate.state1, _val2,
062: bstate.state2);
063: _val2.calculateValue(sel, ctx, bstate.state2, _val1,
064: bstate.state1);
065:
066: if (_val1 instanceof Const
067: && ((Const) _val1).getValue(ctx, bstate.state1) == null)
068: buf.append("1 <> 1");
069: else if (_val2 instanceof Const) {
070: Object o = ((Const) _val2).getValue(ctx, bstate.state2);
071: if (o == null)
072: buf.append("1 <> 1");
073: else {
074: Column col = null;
075: if (_val1 instanceof PCPath) {
076: Column[] cols = ((PCPath) _val1)
077: .getColumns(bstate.state1);
078: if (cols.length == 1)
079: col = cols[0];
080: }
081:
082: _val1.appendTo(sel, ctx, bstate.state1, buf, 0);
083: buf.append(" LIKE ");
084: buf.appendValue(o.toString() + "%", col);
085: }
086: } else {
087: String pre = null;
088: String post = null;
089: DBDictionary dict = ctx.store.getDBDictionary();
090: String func = dict.stringLengthFunction;
091: if (func != null) {
092: int idx = func.indexOf("{0}");
093: pre = func.substring(0, idx);
094: post = func.substring(idx + 3);
095: }
096:
097: // if we can't use LIKE, we have to take the substring of the
098: // first value and compare it to the second
099: dict.assertSupport(pre != null, "StringLengthFunction");
100: dict.substring(buf, new FilterValueImpl(sel, ctx,
101: bstate.state1, _val1), new ZeroFilterValue(sel,
102: state), new StringLengthFilterValue(sel, ctx,
103: bstate.state2, pre, post));
104: buf.append(" = ");
105: _val2.appendTo(sel, ctx, bstate.state2, buf, 0);
106: }
107:
108: sel.append(buf, state.joins);
109: }
110:
111: public void selectColumns(Select sel, ExpContext ctx,
112: ExpState state, boolean pks) {
113: BinaryOpExpState bstate = (BinaryOpExpState) state;
114: _val1.selectColumns(sel, ctx, bstate.state1, true);
115: _val2.selectColumns(sel, ctx, bstate.state2, true);
116: }
117:
118: public void acceptVisit(ExpressionVisitor visitor) {
119: visitor.enter(this );
120: _val1.acceptVisit(visitor);
121: _val2.acceptVisit(visitor);
122: visitor.exit(this );
123: }
124:
125: /**
126: * Evaluates to 0.
127: */
128: private static class ZeroFilterValue implements FilterValue {
129:
130: private final Select _sel;
131: private final ExpState _state;
132:
133: public ZeroFilterValue(Select sel, ExpState state) {
134: _sel = sel;
135: _state = state;
136: }
137:
138: public Class getType() {
139: return int.class;
140: }
141:
142: public int length() {
143: return 1;
144: }
145:
146: public void appendTo(SQLBuffer buf) {
147: appendTo(buf, 0);
148: }
149:
150: public void appendTo(SQLBuffer buf, int index) {
151: buf.appendValue(0);
152: }
153:
154: public String getColumnAlias(Column col) {
155: return _sel.getColumnAlias(col, _state.joins);
156: }
157:
158: public String getColumnAlias(String col, Table table) {
159: return _sel.getColumnAlias(col, table, _state.joins);
160: }
161:
162: public Object toDataStoreValue(Object val) {
163: return val;
164: }
165:
166: public boolean isConstant() {
167: return true;
168: }
169:
170: public Object getValue() {
171: return Numbers.valueOf(0);
172: }
173:
174: public Object getSQLValue() {
175: return Numbers.valueOf(0);
176: }
177:
178: public boolean isPath() {
179: return false;
180: }
181:
182: public ClassMapping getClassMapping() {
183: return null;
184: }
185:
186: public FieldMapping getFieldMapping() {
187: return null;
188: }
189:
190: public PCPath getXPath() {
191: return null;
192: }
193:
194: public XMLMetaData getXmlMapping() {
195: return null;
196: }
197:
198: }
199:
200: /**
201: * Evaluates to the length of a given value.
202: */
203: private class StringLengthFilterValue implements FilterValue {
204:
205: private final Select _sel;
206: private final ExpContext _ctx;
207: private final ExpState _state;
208: private final String _pre;
209: private final String _post;
210:
211: public StringLengthFilterValue(Select sel, ExpContext ctx,
212: ExpState state, String pre, String post) {
213: _sel = sel;
214: _ctx = ctx;
215: _state = state;
216: _pre = pre;
217: _post = post;
218: }
219:
220: public Class getType() {
221: return int.class;
222: }
223:
224: public int length() {
225: return 1;
226: }
227:
228: public void appendTo(SQLBuffer buf) {
229: appendTo(buf, 0);
230: }
231:
232: public void appendTo(SQLBuffer buf, int index) {
233: buf.append(_pre);
234: _val2.appendTo(_sel, _ctx, _state, buf, index);
235: buf.append(_post);
236: }
237:
238: public String getColumnAlias(Column col) {
239: return _sel.getColumnAlias(col, _state.joins);
240: }
241:
242: public String getColumnAlias(String col, Table table) {
243: return _sel.getColumnAlias(col, table, _state.joins);
244: }
245:
246: public Object toDataStoreValue(Object val) {
247: return _val2.toDataStoreValue(_sel, _ctx, _state, val);
248: }
249:
250: public boolean isConstant() {
251: return false;
252: }
253:
254: public Object getValue() {
255: return null;
256: }
257:
258: public Object getSQLValue() {
259: return null;
260: }
261:
262: public boolean isPath() {
263: return false;
264: }
265:
266: public ClassMapping getClassMapping() {
267: return null;
268: }
269:
270: public FieldMapping getFieldMapping() {
271: return null;
272: }
273:
274: public PCPath getXPath() {
275: return null;
276: }
277:
278: public XMLMetaData getXmlMapping() {
279: return null;
280: }
281: }
282: }
|