1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19 package org.apache.openjpa.jdbc.kernel.exps;
20
21 import java.sql.SQLException;
22
23 import org.apache.openjpa.jdbc.kernel.JDBCFetchConfiguration;
24 import org.apache.openjpa.jdbc.meta.ClassMapping;
25 import org.apache.openjpa.jdbc.meta.JavaSQLTypes;
26 import org.apache.openjpa.jdbc.sql.Result;
27 import org.apache.openjpa.jdbc.sql.SQLBuffer;
28 import org.apache.openjpa.jdbc.sql.Select;
29 import org.apache.openjpa.kernel.Filters;
30 import org.apache.openjpa.kernel.exps.ExpressionVisitor;
31 import org.apache.openjpa.kernel.exps.QueryExpressions;
32 import org.apache.openjpa.kernel.exps.Subquery;
33 import org.apache.openjpa.meta.ClassMetaData;
34
35 /**
36 * A subquery.
37 *
38 * @author Abe White
39 */
40 class SubQ
41 extends AbstractVal
42 implements Subquery {
43
44 private final ClassMapping _candidate;
45 private final boolean _subs;
46 private final String _alias;
47 private final SelectConstructor _cons = new SelectConstructor();
48
49 private Class _type = null;
50 private ClassMetaData _meta = null;
51 private QueryExpressions _exps = null;
52
53 /**
54 * Constructor. Supply candidate, whether subclasses are included in
55 * the query, and the query alias.
56 */
57 public SubQ(ClassMapping candidate, boolean subs, String alias) {
58 _candidate = candidate;
59 _subs = subs;
60 _alias = alias;
61 }
62
63 /**
64 * Return the subquery candidate type.
65 */
66 public ClassMapping getCandidate() {
67 return _candidate;
68 }
69
70 public Class getType() {
71 if (_exps != null) {
72 if (_exps.projections.length == 0)
73 return _candidate.getDescribedType();
74 if (_exps.projections.length == 1)
75 return _exps.projections[0].getType();
76 }
77 return _type;
78 }
79
80 public void setImplicitType(Class type) {
81 if (_exps != null && _exps.projections.length == 1)
82 _exps.projections[0].setImplicitType(type);
83 _type = type;
84 }
85
86 public ClassMetaData getMetaData() {
87 return _meta;
88 }
89
90 public void setMetaData(ClassMetaData meta) {
91 _meta = meta;
92 }
93
94 public String getCandidateAlias() {
95 return _alias;
96 }
97
98 public void setQueryExpressions(QueryExpressions query) {
99 _exps = query;
100 }
101
102 public ExpState initialize(Select sel, ExpContext ctx, int flags) {
103 if (_exps.projections.length == 1)
104 return ((Val) _exps.projections[0]).initialize(sel, ctx, flags);
105 return ExpState.NULL;
106 }
107
108 public Object toDataStoreValue(Select sel, ExpContext ctx, ExpState state,
109 Object val) {
110 if (_exps.projections.length == 0)
111 return _candidate.toDataStoreValue(val,
112 _candidate.getPrimaryKeyColumns(), ctx.store);
113 if (_exps.projections.length == 1)
114 return ((Val) _exps.projections[0]).toDataStoreValue(sel, ctx,
115 state, val);
116 return val;
117 }
118
119 public void select(Select sel, ExpContext ctx, ExpState state,
120 boolean pks) {
121 selectColumns(sel, ctx, state, pks);
122 }
123
124 public void selectColumns(Select sel, ExpContext ctx, ExpState state,
125 boolean pks) {
126 sel.select(newSQLBuffer(sel, ctx, state), this);
127 }
128
129 public void groupBy(Select sel, ExpContext ctx, ExpState state) {
130 sel.groupBy(newSQLBuffer(sel, ctx, state));
131 }
132
133 public void orderBy(Select sel, ExpContext ctx, ExpState state,
134 boolean asc) {
135 sel.orderBy(newSQLBuffer(sel, ctx, state), asc, false);
136 }
137
138 private SQLBuffer newSQLBuffer(Select sel, ExpContext ctx, ExpState state) {
139 SQLBuffer buf = new SQLBuffer(ctx.store.getDBDictionary());
140 appendTo(sel, ctx, state, buf, 0);
141 return buf;
142 }
143
144 public Object load(ExpContext ctx, ExpState state, Result res)
145 throws SQLException {
146 return Filters.convert(res.getObject(this,
147 JavaSQLTypes.JDBC_DEFAULT, null), getType());
148 }
149
150 public void calculateValue(Select sel, ExpContext ctx, ExpState state,
151 Val other, ExpState otherState) {
152 }
153
154 public int length(Select sel, ExpContext ctx, ExpState state) {
155 return 1;
156 }
157
158 public void appendTo(Select sel, ExpContext ctx, ExpState state,
159 SQLBuffer sql, int index) {
160 appendTo(sel, ctx, state, sql, index, false);
161 }
162
163 private void appendTo(Select sel, ExpContext ctx, ExpState state,
164 SQLBuffer sql, int index, boolean size) {
165 QueryExpressionsState substate = new QueryExpressionsState();
166 Select sub = _cons.evaluate(ctx, sel, _alias, _exps, substate);
167 _cons.select(sub, ctx, _candidate, _subs, _exps, substate,
168 JDBCFetchConfiguration.EAGER_NONE);
169
170 if (size)
171 sql.appendCount(sub, ctx.fetch);
172 else
173 sql.append(sub, ctx.fetch);
174 }
175
176 public void appendIsEmpty(Select sel, ExpContext ctx, ExpState state,
177 SQLBuffer sql) {
178 sql.append("NOT EXISTS ");
179 appendTo(sel, ctx, state, sql, 0);
180 }
181
182 public void appendIsNotEmpty(Select sel, ExpContext ctx, ExpState state,
183 SQLBuffer sql) {
184 sql.append("EXISTS ");
185 appendTo(sel, ctx, state, sql, 0);
186 }
187
188 public void appendSize(Select sel, ExpContext ctx, ExpState state,
189 SQLBuffer sql) {
190 appendTo(sel, ctx, state, sql, 0, true);
191 }
192
193 public void acceptVisit(ExpressionVisitor visitor) {
194 visitor.enter(this);
195 for (int i = 0; i < _exps.projections.length; i++)
196 _exps.projections[i].acceptVisit(visitor);
197 if (_exps.filter != null)
198 _exps.filter.acceptVisit(visitor);
199 for (int i = 0; i < _exps.grouping.length; i++)
200 _exps.grouping[i].acceptVisit(visitor);
201 if (_exps.having != null)
202 _exps.having.acceptVisit(visitor);
203 for (int i = 0; i < _exps.ordering.length; i++)
204 _exps.ordering[i].acceptVisit(visitor);
205 visitor.exit(this);
206 }
207 }