001: /*
002:
003: Derby - Class org.apache.derby.impl.sql.compile.VirtualColumnNode
004:
005: Licensed to the Apache Software Foundation (ASF) under one or more
006: contributor license agreements. See the NOTICE file distributed with
007: this work for additional information regarding copyright ownership.
008: The ASF licenses this file to you under the Apache License, Version 2.0
009: (the "License"); you may not use this file except in compliance with
010: the License. You may obtain a copy of the License at
011:
012: http://www.apache.org/licenses/LICENSE-2.0
013:
014: Unless required by applicable law or agreed to in writing, software
015: distributed under the License is distributed on an "AS IS" BASIS,
016: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: See the License for the specific language governing permissions and
018: limitations under the License.
019:
020: */
021:
022: package org.apache.derby.impl.sql.compile;
023:
024: import org.apache.derby.iapi.services.compiler.MethodBuilder;
025:
026: import org.apache.derby.iapi.services.sanity.SanityManager;
027:
028: import org.apache.derby.iapi.types.DataTypeDescriptor;
029: import org.apache.derby.iapi.error.StandardException;
030:
031: import org.apache.derby.impl.sql.compile.ExpressionClassBuilder;
032:
033: /**
034: * A VirtualColumnNode represents a virtual column reference to a column in
035: * a row returned by an underlying ResultSetNode. The underlying column could
036: * be in a base table, view (which could expand into a complex
037: * expression), subquery in the FROM clause, temp table, expression result, etc.
038: * By the time we get to code generation, all VirtualColumnNodes should stand only
039: * for references to columns in a base table within a FromBaseTable.
040: *
041: * @author Jeff Lichtman
042: */
043:
044: public class VirtualColumnNode extends ValueNode {
045: /* A VirtualColumnNode contains a pointer to the immediate child result
046: * that is materializing the virtual column and the ResultColumn
047: * that represents that materialization.
048: */
049: ResultSetNode sourceResultSet;
050: ResultColumn sourceColumn;
051:
052: /* columnId is redundant since a ResultColumn also has one, but
053: * we need it here for generate()
054: */
055: int columnId;
056:
057: boolean correlated = false;
058:
059: /**
060: * Initializer for a VirtualColumnNode.
061: *
062: * @param sourceResultSet The ResultSetNode where the value is originating
063: * @param sourceColumn The ResultColumn where the value is originating
064: * @param columnId The columnId within the current Row
065: */
066:
067: public void init(Object sourceResultSet, Object sourceColumn,
068: Object columnId) throws StandardException {
069: ResultColumn source = (ResultColumn) sourceColumn;
070:
071: this .sourceResultSet = (ResultSetNode) sourceResultSet;
072: this .sourceColumn = source;
073: this .columnId = ((Integer) columnId).intValue();
074: setType(source.getTypeServices());
075: }
076:
077: /**
078: * Prints the sub-nodes of this object. See QueryTreeNode.java for
079: * how tree printing is supposed to work.
080: *
081: * @param depth The depth of this node in the tree
082: */
083:
084: public void printSubNodes(int depth) {
085: if (SanityManager.DEBUG) {
086: super .printSubNodes(depth);
087:
088: if (sourceColumn != null) {
089: printLabel(depth, "sourceColumn: ");
090: sourceColumn.treePrint(depth + 1);
091: }
092: }
093: }
094:
095: /**
096: * Return the ResultSetNode that is the source of this VirtualColumnNode.
097: *
098: * @return ResultSetNode
099: */
100: public ResultSetNode getSourceResultSet() {
101: return sourceResultSet;
102: }
103:
104: /**
105: * Return the ResultColumn that is the source of this VirtualColumnNode.
106: *
107: * @return ResultSetNode
108: */
109: public ResultColumn getSourceColumn() {
110: return sourceColumn;
111: }
112:
113: /**
114: * Get the name of the table the ResultColumn is in, if any. This will be null
115: * if the user did not supply a name (for example, select a from t).
116: * The method will return B for this example, select b.a from t as b
117: * The method will return T for this example, select t.a from t
118: *
119: * @return A String containing the name of the table the Column
120: * is in. If the column is not in a table (i.e. is a
121: * derived column), it returns NULL.
122: */
123: public String getTableName() {
124: return ((sourceColumn != null) ? sourceColumn.getTableName()
125: : null);
126: }
127:
128: /**
129: * Get the name of the schema the ResultColumn's table is in, if any.
130: * The return value will be null if the user did not supply a schema name
131: * (for example, select t.a from t).
132: * Another example for null return value (for example, select b.a from t as b).
133: * But for following query select app.t.a from t, this will return APP
134: *
135: * @return A String containing the name of the schema for the Column's table.
136: * If the column is not in a schema (i.e. derived column), it returns NULL.
137: */
138: public String getSchemaName() throws StandardException {
139: return ((sourceColumn != null) ? sourceColumn.getSchemaName()
140: : null);
141: }
142:
143: /**
144: * Return whether or not the ResultColumn is wirtable by a positioned update.
145: *
146: * @return TRUE, if the column is a base column of a table and is
147: * writable by a positioned update.
148: */
149: public boolean updatableByCursor() {
150: return ((sourceColumn != null) ? sourceColumn
151: .updatableByCursor() : false);
152: }
153:
154: /**
155: * Return the ResultColumn that is the source of this VirtualColumnNode.
156: *
157: * @return ResultSetNode
158: */
159: public ResultColumn getSourceResultColumn() {
160: return sourceColumn;
161: }
162:
163: /**
164: * Mark this VCN as a reference to a correlated column.
165: * (It's source resultSet is an outer ResultSet.
166: */
167: void setCorrelated() {
168: correlated = true;
169: }
170:
171: /**
172: * Return whether or not this VCN is a correlated reference.
173: *
174: * @return Whether or not this VCN is a correlated reference.
175: */
176: boolean getCorrelated() {
177: return correlated;
178: }
179:
180: /**
181: * Return whether or not this expression tree is cloneable.
182: *
183: * @return boolean Whether or not this expression tree is cloneable.
184: */
185: public boolean isCloneable() {
186: return true;
187: }
188:
189: /**
190: * ColumnNode's are against the current row in the system.
191: * This lets us generate
192: * a faster get that simply returns the column from the
193: * current row, rather than getting the value out and
194: * returning that, only to have the caller (in the situations
195: * needed) stuffing it back into a new column holder object.
196: * We will assume the general generate() path is for getting
197: * the value out, and use generateColumn() when we want to
198: * keep the column wrapped.
199: *
200: * @exception StandardException Thrown on error
201: */
202: public void generateExpression(ExpressionClassBuilder acb,
203: MethodBuilder mb) throws StandardException {
204: int sourceResultSetNumber = sourceColumn.getResultSetNumber();
205:
206: /* If the source is marked as redundant, then continue down
207: * the RC/VirtualColumnNode chain.
208: */
209: if (sourceColumn.isRedundant()) {
210: sourceColumn.getExpression().generateExpression(acb, mb);
211: return;
212: }
213:
214: if (SanityManager.DEBUG)
215: SanityManager.ASSERT(sourceResultSetNumber >= 0,
216: "sourceResultSetNumber expected to be >= 0 for virtual column "
217: + sourceColumn.getName());
218:
219: /* The ColumnReference is from an immediately underlying ResultSet.
220: * The Row for that ResultSet is Activation.row[sourceResultSetNumber],
221: * where sourceResultSetNumber is the resultSetNumber for that ResultSet.
222: *
223: * The generated java is the expression:
224: * (<Datatype interface>) this.row[sourceResultSetNumber].
225: * getColumn(#columnId);
226: * where <Datatype interface> is the appropriate interface for the
227: * column from the Datatype protocol.
228: */
229: acb.pushColumnReference(mb, sourceResultSetNumber, sourceColumn
230: .getVirtualColumnId());
231:
232: mb.cast(sourceColumn.getTypeCompiler().interfaceName());
233: }
234:
235: /**
236: * Return the variant type for the underlying expression.
237: * The variant type can be:
238: * VARIANT - variant within a scan
239: * (method calls and non-static field access)
240: * SCAN_INVARIANT - invariant within a scan
241: * (column references from outer tables)
242: * QUERY_INVARIANT - invariant within the life of a query
243: * (constant expressions)
244: *
245: * @return The variant type for the underlying expression.
246: * @exception StandardException thrown on error
247: */
248: protected int getOrderableVariantType() throws StandardException {
249: /*
250: ** Delegate to the source column
251: */
252: return sourceColumn.getOrderableVariantType();
253: }
254:
255: /**
256: * Get the DataTypeServices from this Node.
257: *
258: * @return The DataTypeServices from this Node. This
259: * may be null if the node isn't bound yet.
260: */
261: public DataTypeDescriptor getTypeServices()
262: throws StandardException {
263: DataTypeDescriptor dtd = super .getTypeServices();
264: if (dtd == null && sourceColumn != null) {
265: dtd = sourceColumn.getTypeServices();
266: if (dtd != null)
267: setType(dtd);
268: }
269: return dtd;
270: } // end of getTypeServices
271:
272: protected boolean isEquivalent(ValueNode o)
273: throws StandardException {
274: if (isSameNodeType(o)) {
275: VirtualColumnNode other = (VirtualColumnNode) o;
276: return sourceColumn.isEquivalent(other.sourceColumn);
277: }
278: return false;
279: }
280: }
|