0001: /*
0002:
0003: Derby - Class org.apache.derby.impl.sql.compile.ResultColumn
0004:
0005: Licensed to the Apache Software Foundation (ASF) under one or more
0006: contributor license agreements. See the NOTICE file distributed with
0007: this work for additional information regarding copyright ownership.
0008: The ASF licenses this file to you under the Apache License, Version 2.0
0009: (the "License"); you may not use this file except in compliance with
0010: the License. You may obtain a copy of the License at
0011:
0012: http://www.apache.org/licenses/LICENSE-2.0
0013:
0014: Unless required by applicable law or agreed to in writing, software
0015: distributed under the License is distributed on an "AS IS" BASIS,
0016: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0017: See the License for the specific language governing permissions and
0018: limitations under the License.
0019:
0020: */
0021:
0022: package org.apache.derby.impl.sql.compile;
0023:
0024: import org.apache.derby.iapi.services.compiler.MethodBuilder;
0025:
0026: import org.apache.derby.iapi.services.sanity.SanityManager;
0027: import org.apache.derby.iapi.services.context.ContextManager;
0028:
0029: import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
0030:
0031: import org.apache.derby.iapi.types.DataTypeDescriptor;
0032: import org.apache.derby.iapi.types.DataValueDescriptor;
0033: import org.apache.derby.iapi.types.StringDataValue;
0034: import org.apache.derby.iapi.sql.ResultColumnDescriptor;
0035: import org.apache.derby.iapi.types.DataTypeDescriptor;
0036: import org.apache.derby.iapi.types.DataValueDescriptor;
0037: import org.apache.derby.iapi.types.TypeId;
0038: import org.apache.derby.iapi.services.io.StoredFormatIds;
0039: import org.apache.derby.iapi.types.DataValueFactory;
0040:
0041: import org.apache.derby.iapi.sql.dictionary.DataDictionary;
0042: import org.apache.derby.iapi.sql.dictionary.TableDescriptor;
0043: import org.apache.derby.iapi.sql.dictionary.ColumnDescriptor;
0044:
0045: import org.apache.derby.iapi.sql.compile.CompilerContext;
0046: import org.apache.derby.iapi.sql.compile.RowOrdering;
0047: import org.apache.derby.iapi.sql.compile.Visitable;
0048: import org.apache.derby.iapi.sql.compile.Visitor;
0049: import org.apache.derby.iapi.sql.compile.C_NodeTypes;
0050:
0051: import org.apache.derby.impl.sql.compile.ActivationClassBuilder;
0052: import org.apache.derby.impl.sql.compile.ExpressionClassBuilder;
0053:
0054: import org.apache.derby.iapi.store.access.Qualifier;
0055:
0056: import org.apache.derby.iapi.error.StandardException;
0057: import org.apache.derby.iapi.reference.SQLState;
0058: import org.apache.derby.iapi.reference.ClassName;
0059:
0060: import org.apache.derby.iapi.util.JBitSet;
0061: import org.apache.derby.iapi.util.StringUtil;
0062:
0063: import java.sql.Types;
0064:
0065: import java.util.Vector;
0066:
0067: /**
0068: * A ResultColumn represents a result column in a SELECT, INSERT, or UPDATE
0069: * statement. In a SELECT statement, the result column just represents an
0070: * expression in a row being returned to the client. For INSERT and UPDATE
0071: * statements, the result column represents an column in a stored table.
0072: * So, a ResultColumn has to be bound differently depending on the type of
0073: * statement it appears in.
0074: *
0075: * @author Jeff Lichtman
0076: */
0077:
0078: public class ResultColumn extends ValueNode implements
0079: ResultColumnDescriptor, Comparable {
0080: /* name and exposedName should point to the same string, unless there is a
0081: * derived column list, in which case name will point to the underlying name
0082: * and exposedName will point to the name from the derived column list.
0083: */
0084: String name;
0085: String exposedName;
0086: String tableName;
0087: String sourceTableName;
0088: //Used by metadata api ResultSetMetaData.getSchemaName to get a column's table's schema.
0089: String sourceSchemaName;
0090: ValueNode expression;
0091: ColumnDescriptor columnDescriptor;
0092: boolean isGenerated;
0093: boolean isGeneratedForUnmatchedColumnInInsert;
0094: boolean isGroupingColumn;
0095: boolean isReferenced;
0096: boolean isRedundant;
0097: boolean isNameGenerated;
0098: boolean updated;
0099: boolean updatableByCursor;
0100: private boolean defaultColumn;
0101:
0102: // tells us if this ResultColumn is a placeholder for a generated
0103: // autoincrement value for an insert statement.
0104: boolean autoincrementGenerated;
0105:
0106: // tells us if this ResultColumn represents an autoincrement column in a
0107: // base table.
0108: boolean autoincrement;
0109:
0110: /* ResultSetNumber for the ResultSet (at generate() time) that we belong to */
0111: private int resultSetNumber = -1;
0112: ColumnReference reference; // used to verify quals at bind time, if given.
0113:
0114: /* virtualColumnId is the ResultColumn's position (1-based) within the ResultSet */
0115: private int virtualColumnId;
0116:
0117: /**
0118: * Different types of initializer parameters indicate different
0119: * types of initialization. Parameters may be:
0120: *
0121: * <ul>
0122: * <li>arg1 The name of the column, if any.</li>
0123: * <li>arg2 The expression this result column represents</li>
0124: * </ul>
0125: *
0126: * <p>
0127: * - OR -
0128: * </p>
0129: *
0130: * <ul>
0131: * <li>arg1 a column reference node</li>
0132: * <li>arg2 The expression this result column represents</li>
0133: * </ul>
0134: *
0135: * <p>
0136: * - OR -
0137: * </p>
0138: *
0139: * <ul>
0140: * <li>arg1 The column descriptor.</li>
0141: * <li>arg2 The expression this result column represents</li>
0142: * </ul>
0143: *
0144: * <p>
0145: * - OR -
0146: * </p>
0147: *
0148: * <ul>
0149: * <li>dtd The type of the column</li>
0150: * <li>expression The expression this result column represents</li>
0151: * </ul>
0152: */
0153: public void init(Object arg1, Object arg2) throws StandardException {
0154: // RESOLVE: This is something of a hack - it is not obvious that
0155: // the first argument being null means it should be treated as
0156: // a String.
0157: if ((arg1 instanceof String) || (arg1 == null)) {
0158: this .name = (String) arg1;
0159: this .exposedName = this .name;
0160: this .expression = (ValueNode) arg2;
0161: } else if (arg1 instanceof ColumnReference) {
0162: ColumnReference ref = (ColumnReference) arg1;
0163:
0164: this .name = ref.getColumnName();
0165: this .exposedName = ref.getColumnName();
0166: /*
0167: when we bind, we'll want to make sure
0168: the reference has the right table name.
0169: */
0170: this .reference = ref;
0171: this .expression = (ValueNode) arg2;
0172: } else if (arg1 instanceof ColumnDescriptor) {
0173: ColumnDescriptor coldes = (ColumnDescriptor) arg1;
0174: DataTypeDescriptor colType = coldes.getType();
0175:
0176: this .name = coldes.getColumnName();
0177: this .exposedName = name;
0178: /* Clone the type info here, so we can change nullability if needed */
0179: setType(new DataTypeDescriptor(colType, colType
0180: .isNullable()));
0181: this .columnDescriptor = coldes;
0182: this .expression = (ValueNode) arg2;
0183: this .autoincrement = coldes.isAutoincrement();
0184: } else {
0185: setType((DataTypeDescriptor) arg1);
0186: this .expression = (ValueNode) arg2;
0187: if (arg2 instanceof ColumnReference) {
0188: reference = (ColumnReference) arg2;
0189: }
0190: }
0191:
0192: /* this result column represents a <default> keyword in an insert or
0193: * update statement
0194: */
0195: if (expression != null
0196: && expression.isInstanceOf(C_NodeTypes.DEFAULT_NODE))
0197: defaultColumn = true;
0198: }
0199:
0200: /**
0201: * Returns TRUE if the ResultColumn is standing in for a DEFAULT keyword in
0202: * an insert/update statement.
0203: */
0204: public boolean isDefaultColumn() {
0205: return defaultColumn;
0206: }
0207:
0208: public void setDefaultColumn(boolean value) {
0209: defaultColumn = value;
0210: }
0211:
0212: /**
0213: * The following methods implement the ResultColumnDescriptor
0214: * interface. See the Language Module Interface for details.
0215: */
0216:
0217: public String getName() {
0218: return exposedName;
0219: }
0220:
0221: public String getSchemaName() throws StandardException {
0222: if ((columnDescriptor != null)
0223: && (columnDescriptor.getTableDescriptor() != null))
0224: return columnDescriptor.getTableDescriptor()
0225: .getSchemaName();
0226: else {
0227: if (expression != null)
0228: // REMIND: could look in reference, if set.
0229: return expression.getSchemaName();
0230: else
0231: return null;
0232: }
0233: }
0234:
0235: public String getTableName() {
0236: if (tableName != null) {
0237: return tableName;
0238: }
0239: if ((columnDescriptor != null)
0240: && (columnDescriptor.getTableDescriptor() != null)) {
0241: return columnDescriptor.getTableDescriptor().getName();
0242: } else {
0243: return expression.getTableName();
0244: }
0245: }
0246:
0247: /**
0248: * @see ResultColumnDescriptor#getSourceTableName
0249: */
0250: public String getSourceTableName() {
0251: return sourceTableName;
0252: }
0253:
0254: /**
0255: * @see ResultColumnDescriptor#getSourceSchemaName
0256: */
0257: public String getSourceSchemaName() {
0258: return sourceSchemaName;
0259: }
0260:
0261: /**
0262: * Clear the table name for the underlying ColumnReference.
0263: * See UpdateNode.scrubResultColumns() for full explaination.
0264: */
0265: public void clearTableName() {
0266: if (expression instanceof ColumnReference) {
0267: ((ColumnReference) expression)
0268: .setTableNameNode((TableName) null);
0269: }
0270: }
0271:
0272: public DataTypeDescriptor getType() {
0273: return dataTypeServices;
0274: }
0275:
0276: public DataTypeDescriptor getExpressionType()
0277: throws StandardException {
0278: return (expression == null) ? dataTypeServices : expression
0279: .getTypeServices();
0280: }
0281:
0282: public int getColumnPosition() {
0283: if (columnDescriptor != null)
0284: return columnDescriptor.getPosition();
0285: else
0286: return virtualColumnId;
0287:
0288: }
0289:
0290: /**
0291: * Set the expression in this ResultColumn. This is useful in those
0292: * cases where you don't know the expression in advance, like for
0293: * INSERT statements with column lists, where the column list and
0294: * SELECT or VALUES clause are parsed separately, and then have to
0295: * be hooked up.
0296: *
0297: * @param expression The expression to be set in this ResultColumn
0298: */
0299:
0300: public void setExpression(ValueNode expression) {
0301: this .expression = expression;
0302: }
0303:
0304: /**
0305: * Get the expression in this ResultColumn.
0306: *
0307: * @return ValueNode this.expression
0308: */
0309:
0310: public ValueNode getExpression() {
0311: return expression;
0312: }
0313:
0314: /**
0315: * Set the expression to a null node of the
0316: * correct type.
0317: *
0318: * @exception StandardException Thrown on error
0319: */
0320: void setExpressionToNullNode() throws StandardException {
0321: expression = getNullNode(getTypeId(), getContextManager());
0322: }
0323:
0324: /**
0325: * Set the name in this ResultColumn. This is useful when you don't
0326: * know the name at the time you create the ResultColumn, for example,
0327: * in an insert-select statement, where you want the names of the
0328: * result columns to match the table being inserted into, not the
0329: * table they came from.
0330: *
0331: * @param name The name to set in this ResultColumn
0332: */
0333:
0334: public void setName(String name) {
0335: if (this .name == null) {
0336: this .name = name;
0337: } else {
0338: if (SanityManager.DEBUG)
0339: SanityManager.ASSERT(reference == null
0340: || name.equals(reference.getColumnName()),
0341: "don't change name from reference name");
0342: }
0343:
0344: this .exposedName = name;
0345: }
0346:
0347: /**
0348: * Is the name for this ResultColumn generated?
0349: */
0350: public boolean isNameGenerated() {
0351: return isNameGenerated;
0352: }
0353:
0354: /**
0355: * Set that this result column name is generated.
0356: */
0357: public void setNameGenerated(boolean value) {
0358: isNameGenerated = value;
0359: }
0360:
0361: /**
0362: * Set the resultSetNumber for this ResultColumn. This is the
0363: * resultSetNumber for the ResultSet that we belong to. This
0364: * is useful for generate() and necessary since we do not have a
0365: * back pointer to the RSN.
0366: *
0367: * @param resultSetNumber The resultSetNumber.
0368: */
0369: public void setResultSetNumber(int resultSetNumber) {
0370: this .resultSetNumber = resultSetNumber;
0371: }
0372:
0373: /**
0374: * Get the resultSetNumber for this ResultColumn.
0375: *
0376: * @return int The resultSetNumber.
0377: */
0378: public int getResultSetNumber() {
0379: return resultSetNumber;
0380: }
0381:
0382: /**
0383: * Set the clause that this node appears in.
0384: *
0385: * @param clause The clause that this node appears in.
0386: */
0387: public void setClause(int clause) {
0388: super .setClause(clause);
0389: /* expression will be null for AllResultColumn */
0390: if (expression != null) {
0391: expression.setClause(clause);
0392: } else if (SanityManager.DEBUG) {
0393: SanityManager
0394: .ASSERT(this instanceof AllResultColumn,
0395: "this expected to be instanceof AllResultColumn when expression is null");
0396: }
0397: }
0398:
0399: /**
0400: * Adjust the virtualColumnId for this ResultColumn by the specified amount
0401: *
0402: * @param adjust The adjustment for the virtualColumnId
0403: */
0404:
0405: public void adjustVirtualColumnId(int adjust) {
0406: virtualColumnId += adjust;
0407: }
0408:
0409: /**
0410: * Set the virtualColumnId for this ResultColumn
0411: *
0412: * @param id The virtualColumnId for this ResultColumn
0413: */
0414:
0415: public void setVirtualColumnId(int id) {
0416: virtualColumnId = id;
0417: }
0418:
0419: /**
0420: * Get the virtualColumnId for this ResultColumn
0421: *
0422: * @return virtualColumnId for this ResultColumn
0423: */
0424: public int getVirtualColumnId() {
0425: return virtualColumnId;
0426: }
0427:
0428: /**
0429: * Generate a unique (across the entire statement) column name for unnamed
0430: * ResultColumns
0431: *
0432: * @exception StandardException Thrown on error
0433: */
0434: public void guaranteeColumnName() throws StandardException {
0435: if (exposedName == null) {
0436: /* Unions may also need generated names, if both sides name don't match */
0437: exposedName = "SQLCol"
0438: + getCompilerContext().getNextColumnNumber();
0439: isNameGenerated = true;
0440: }
0441: }
0442:
0443: /**
0444: * Convert this object to a String. See comments in QueryTreeNode.java
0445: * for how this should be done for tree printing.
0446: *
0447: * @return This object as a String
0448: */
0449:
0450: public String toString() {
0451: if (SanityManager.DEBUG) {
0452: return "exposedName: " + exposedName + "\n" + "name: "
0453: + name + "\n" + "tableName: " + tableName + "\n"
0454: + "isNameGenerated: " + isNameGenerated + "\n"
0455: + "sourceTableName: " + sourceTableName + "\n"
0456: + "type: " + dataTypeServices + "\n"
0457: + "columnDescriptor: " + columnDescriptor + "\n"
0458: + "isGenerated: " + isGenerated + "\n"
0459: + "isGeneratedForUnmatchedColumnInInsert: "
0460: + isGeneratedForUnmatchedColumnInInsert + "\n"
0461: + "isGroupingColumn: " + isGroupingColumn + "\n"
0462: + "isReferenced: " + isReferenced + "\n"
0463: + "isRedundant: " + isRedundant + "\n"
0464: + "virtualColumnId: " + virtualColumnId + "\n"
0465: + "resultSetNumber: " + resultSetNumber + "\n"
0466: + super .toString();
0467: } else {
0468: return "";
0469: }
0470: }
0471:
0472: /**
0473: * Prints the sub-nodes of this object. See QueryTreeNode.java for
0474: * how tree printing is supposed to work.
0475: *
0476: * @param depth The depth of this node in the tree
0477: */
0478:
0479: public void printSubNodes(int depth) {
0480: if (SanityManager.DEBUG) {
0481: super .printSubNodes(depth);
0482: if (expression != null) {
0483: printLabel(depth, "expression: ");
0484: expression.treePrint(depth + 1);
0485: }
0486: if (reference != null) {
0487: printLabel(depth, "reference: ");
0488: reference.treePrint(depth + 1);
0489: }
0490: }
0491: }
0492:
0493: /**
0494: * Bind this expression. This means binding the sub-expressions.
0495: * In this case, we figure out what the result type of this result
0496: * column is when we call one of the bindResultColumn*() methods.
0497: * The reason is that there are different ways of binding the
0498: * result columns depending on the statement type, and this is
0499: * a standard interface that does not take the statement type as
0500: * a parameter.
0501: *
0502: * @param fromList The FROM list for the query this
0503: * expression is in, for binding columns.
0504: * @param subqueryList The subquery list being built as we find SubqueryNodes
0505: * @param aggregateVector The aggregate vector being built as we find AggregateNodes
0506: *
0507: * @return The new top of the expression tree.
0508: *
0509: * @exception StandardException Thrown on error
0510: */
0511:
0512: public ValueNode bindExpression(FromList fromList,
0513: SubqueryList subqueryList, Vector aggregateVector)
0514: throws StandardException {
0515: /*
0516: ** Set the type of a parameter to the type of the result column.
0517: ** Don't do it if this result column doesn't have a type yet.
0518: ** This can happen if the parameter is part of a table constructor.
0519: */
0520: if (expression.requiresTypeFromContext()) {
0521: if (getTypeServices() != null) {
0522: expression.setType(getTypeServices());
0523: }
0524: }
0525:
0526: expression = expression.bindExpression(fromList, subqueryList,
0527: aggregateVector);
0528:
0529: if (expression instanceof ColumnReference) {
0530: autoincrement = ((ColumnReference) expression).getSource()
0531: .isAutoincrement();
0532: }
0533:
0534: return this ;
0535: }
0536:
0537: /**
0538: * Bind this result column by ordinal position and set the VirtualColumnId.
0539: * This is useful for INSERT statements like "insert into t values (1, 2, 3)",
0540: * where the user did not specify a column list.
0541: * If a columnDescriptor is not found for a given position, then
0542: * the user has specified more values than the # of columns in
0543: * the table and an exception is thrown.
0544: *
0545: * NOTE: We must set the VirtualColumnId here because INSERT does not
0546: * construct the ResultColumnList in the usual way.
0547: *
0548: * @param tableDescriptor The descriptor for the table being
0549: * inserted into
0550: * @param columnId The ordinal position of the column
0551: * in the table, starting at 1.
0552: *
0553: * @exception StandardException Thrown on error
0554: */
0555:
0556: void bindResultColumnByPosition(TableDescriptor tableDescriptor,
0557: int columnId) throws StandardException {
0558: ColumnDescriptor columnDescriptor;
0559:
0560: columnDescriptor = tableDescriptor
0561: .getColumnDescriptor(columnId);
0562:
0563: if (columnDescriptor == null) {
0564: String errorString;
0565: String schemaName;
0566:
0567: errorString = "";
0568: schemaName = tableDescriptor.getSchemaName();
0569: if (schemaName != null)
0570: errorString += schemaName + ".";
0571: errorString += tableDescriptor.getName();
0572:
0573: throw StandardException.newException(
0574: SQLState.LANG_TOO_MANY_RESULT_COLUMNS, errorString);
0575: }
0576:
0577: setColumnDescriptor(tableDescriptor, columnDescriptor);
0578: setVirtualColumnId(columnId);
0579: }
0580:
0581: /**
0582: * Bind this result column by its name and set the VirtualColumnId.
0583: * This is useful for update statements, and for INSERT statements
0584: * like "insert into t (a, b, c) values (1, 2, 3)" where the user
0585: * specified a column list.
0586: * An exception is thrown when a columnDescriptor cannot be found for a
0587: * given name. (There is no column with that name.)
0588: *
0589: * NOTE: We must set the VirtualColumnId here because INSERT does not
0590: * construct the ResultColumnList in the usual way.
0591: *
0592: * @param tableDescriptor The descriptor for the table being
0593: * updated or inserted into
0594: * @param columnId The ordinal position of the column
0595: * in the table, starting at 1. (Used to
0596: * set the VirtualColumnId.)
0597: *
0598: * @exception StandardException Thrown on error
0599: */
0600:
0601: public void bindResultColumnByName(TableDescriptor tableDescriptor,
0602: int columnId) throws StandardException {
0603: ColumnDescriptor columnDescriptor;
0604:
0605: columnDescriptor = tableDescriptor
0606: .getColumnDescriptor(exposedName);
0607:
0608: if (columnDescriptor == null) {
0609: String errorString;
0610: String schemaName;
0611:
0612: errorString = "";
0613: schemaName = tableDescriptor.getSchemaName();
0614: if (schemaName != null)
0615: errorString += schemaName + ".";
0616: errorString += tableDescriptor.getName();
0617:
0618: throw StandardException.newException(
0619: SQLState.LANG_COLUMN_NOT_FOUND_IN_TABLE,
0620: exposedName, errorString);
0621: }
0622:
0623: setColumnDescriptor(tableDescriptor, columnDescriptor);
0624: setVirtualColumnId(columnId);
0625: if (isPrivilegeCollectionRequired())
0626: getCompilerContext()
0627: .addRequiredColumnPriv(columnDescriptor);
0628: }
0629:
0630: /**
0631: * Change an untyped null to a typed null.
0632: *
0633: * @exception StandardException Thrown on error
0634: */
0635: public void typeUntypedNullExpression(ResultColumn bindingRC)
0636: throws StandardException {
0637: TypeId typeId = bindingRC.getTypeId();
0638: /* This is where we catch null in a VALUES clause outside
0639: * of INSERT VALUES()
0640: */
0641: if (typeId == null) {
0642: throw StandardException
0643: .newException(SQLState.LANG_NULL_IN_VALUES_CLAUSE);
0644: }
0645:
0646: if (expression instanceof UntypedNullConstantNode)
0647: expression = getNullNode(typeId, getContextManager());
0648: else if ((expression instanceof ColumnReference)
0649: && expression.getTypeServices() == null) {
0650: // The expression must be a reference to a null column in a values table.
0651: expression.setType(bindingRC.getType());
0652: }
0653: }
0654:
0655: /**
0656: * Set the column descriptor for this result column. It also gets
0657: * the data type services from the column descriptor and stores it in
0658: * this result column: this is redundant, but we have to store the result
0659: * type here for SELECT statements, and it is more orthogonal if the type
0660: * can be found here regardless of what type of statement it is.
0661: *
0662: * @param tableDescriptor The TableDescriptor for the table
0663: * being updated or inserted into.
0664: * This parameter is used only for
0665: * error reporting.
0666: * @param columnDescriptor The ColumnDescriptor to set in
0667: * this ResultColumn.
0668: *
0669: * @exception StandardException tableNameMismatch
0670: */
0671: void setColumnDescriptor(TableDescriptor tableDescriptor,
0672: ColumnDescriptor columnDescriptor) throws StandardException {
0673: /* Callers are responsible for verifying that the column exists */
0674: if (SanityManager.DEBUG)
0675: SanityManager
0676: .ASSERT(columnDescriptor != null,
0677: "Caller is responsible for verifying that column exists");
0678:
0679: setType(columnDescriptor.getType());
0680: this .columnDescriptor = columnDescriptor;
0681:
0682: /*
0683: If the node was created using a reference, the table name
0684: of the reference must agree with that of the tabledescriptor.
0685: */
0686: if (reference != null && reference.getTableName() != null) {
0687: if (!tableDescriptor.getName().equals(
0688: reference.getTableName())) {
0689: /* REMIND: need to have schema name comparison someday as well...
0690: ** left out for now, lots of null checking needed...
0691: ** || ! tableDescriptor.getSchemaName().equals(
0692: ** reference.getTableNameNode().getSchemaName())) {
0693: */
0694: String realName = tableDescriptor.getName();
0695: String refName = reference.getTableName();
0696:
0697: throw StandardException.newException(
0698: SQLState.LANG_TABLE_NAME_MISMATCH, realName,
0699: refName);
0700: }
0701: }
0702: }
0703:
0704: /**
0705: * Bind the result column to the expression that lives under it.
0706: * All this does is copy the datatype information to this node.
0707: * This is useful for SELECT statements, where the result type
0708: * of each column is the type of the column's expression.
0709: *
0710: * @exception StandardException Thrown on error
0711: */
0712: public void bindResultColumnToExpression() throws StandardException {
0713: /*
0714: ** This gets the same DataTypeServices object as
0715: ** is used in the expression. It is probably not
0716: ** necessary to clone the object here.
0717: */
0718: setType(expression.getTypeServices());
0719:
0720: if (expression instanceof ColumnReference) {
0721: ColumnReference cr = (ColumnReference) expression;
0722: tableName = cr.getTableName();
0723: sourceTableName = cr.getSourceTableName();
0724: sourceSchemaName = cr.getSourceSchemaName();
0725: }
0726: }
0727:
0728: /**
0729: * Preprocess an expression tree. We do a number of transformations
0730: * here (including subqueries, IN lists, LIKE and BETWEEN) plus
0731: * subquery flattening.
0732: * NOTE: This is done before the outer ResultSetNode is preprocessed.
0733: *
0734: * @param numTables Number of tables in the DML Statement
0735: * @param outerFromList FromList from outer query block
0736: * @param outerSubqueryList SubqueryList from outer query block
0737: * @param outerPredicateList PredicateList from outer query block
0738: *
0739: * @return The modified expression
0740: *
0741: * @exception StandardException Thrown on error
0742: */
0743: public ValueNode preprocess(int numTables, FromList outerFromList,
0744: SubqueryList outerSubqueryList,
0745: PredicateList outerPredicateList) throws StandardException {
0746: if (expression == null)
0747: return this ;
0748: expression = expression.preprocess(numTables, outerFromList,
0749: outerSubqueryList, outerPredicateList);
0750: return this ;
0751: }
0752:
0753: /**
0754: This verifies that the expression is storable into the result column.
0755: It checks versus the given ResultColumn.
0756:
0757: This method should not be called until the result column and
0758: expression both have a valid type, i.e. after they are bound
0759: appropriately. Its use is for statements like insert, that need to
0760: verify if a given value can be stored into a column.
0761:
0762: @exception StandardException thrown if types not suitable.
0763: */
0764: public void checkStorableExpression(ResultColumn toStore)
0765: throws StandardException {
0766: TypeId columnTypeId, toStoreTypeId;
0767:
0768: toStoreTypeId = toStore.getTypeId();
0769: if (toStoreTypeId == null)
0770: return;
0771:
0772: columnTypeId = getTypeId();
0773:
0774: if (!getTypeCompiler().storable(toStoreTypeId,
0775: getClassFactory()))
0776: throw StandardException.newException(
0777: SQLState.LANG_NOT_STORABLE, columnTypeId
0778: .getSQLTypeName(), toStoreTypeId
0779: .getSQLTypeName());
0780: }
0781:
0782: /**
0783: This verifies that the expression is storable into the result column.
0784: It checks versus the expression under this ResultColumn.
0785:
0786: This method should not be called until the result column and
0787: expression both have a valid type, i.e. after they are bound
0788: appropriately. Its use is for statements like update, that need to
0789: verify if a given value can be stored into a column.
0790:
0791: @exception StandardException thrown if types not suitable.
0792: */
0793: public void checkStorableExpression() throws StandardException {
0794: TypeId columnTypeId = getTypeId();
0795: TypeId toStoreTypeId = getExpressionType().getTypeId();
0796:
0797: if (!getTypeCompiler().storable(toStoreTypeId,
0798: getClassFactory()))
0799: throw StandardException.newException(
0800: SQLState.LANG_NOT_STORABLE, columnTypeId
0801: .getSQLTypeName(), toStoreTypeId
0802: .getSQLTypeName());
0803: }
0804:
0805: /**
0806: * Do code generation for a result column. This consists of doing the code
0807: * generation for the underlying expression.
0808: *
0809: * @param ecb The ExpressionClassBuilder for the class we're generating
0810: * @param mb The method the expression will go into
0811: *
0812: *
0813: * @exception StandardException Thrown on error
0814: */
0815:
0816: public void generateExpression(ExpressionClassBuilder ecb,
0817: MethodBuilder mb) throws StandardException {
0818: expression.generateExpression(ecb, mb);
0819: }
0820:
0821: /**
0822: * Do code generation to return a Null of the appropriate type
0823: * for the result column.
0824: Requires the getCOlumnExpress value pushed onto the stack
0825: *
0826: * @param acb The ActivationClassBuilder for the class we're generating
0827: * @param eb The ExpressionBlock that the generate code is to go into
0828: * @param getColumnExpression "fieldx.getColumn(y)"
0829: *
0830: * @exception StandardException Thrown on error
0831: */
0832: /*PUSHCOMPILE
0833: public void generateNulls(ExpressionClassBuilder acb,
0834: MethodBuilder mb,
0835: Expression getColumnExpress)
0836: throws StandardException
0837: {
0838:
0839: acb.pushDataValueFactory(mb);
0840: getTypeCompiler().generateNull(mb, acb.getBaseClassName());
0841:
0842:
0843: mb.cast(ClassName.DataValueDescriptor);
0844:
0845:
0846: return eb.newCastExpression(
0847: ClassName.DataValueDescriptor,
0848: getTypeCompiler().
0849: generateNull(
0850: eb,
0851: acb.getBaseClassName(),
0852: acb.getDataValueFactory(eb),
0853: getColumnExpress));
0854: }
0855: */
0856: /**
0857: Generate the code to create a column the same shape and
0858: size as this ResultColumn.
0859:
0860: Used in ResultColumnList.generateHolder().
0861:
0862: @exception StandardException thrown on failure
0863: */
0864: public void generateHolder(ExpressionClassBuilder acb,
0865: MethodBuilder mb) throws StandardException {
0866: // generate expression of the form
0867: // (DataValueDescriptor) columnSpace
0868:
0869: acb.generateNull(mb, getTypeCompiler());
0870: mb.upCast(ClassName.DataValueDescriptor);
0871: }
0872:
0873: /*
0874: ** Check whether the column length and type of this result column
0875: ** match the expression under the columns. This is useful for
0876: ** INSERT and UPDATE statements. For SELECT statements this method
0877: ** should always return true. There is no need to call this for a
0878: ** DELETE statement.
0879: **
0880: ** @return true means the column matches its expressions,
0881: ** false means it doesn't match.
0882: */
0883:
0884: boolean columnTypeAndLengthMatch() throws StandardException {
0885: DataTypeDescriptor resultColumnType;
0886: DataTypeDescriptor expressionType = expression
0887: .getTypeServices();
0888:
0889: /*
0890: ** We can never make any assumptions about
0891: ** parameters. So don't even bother in this
0892: ** case.
0893: */
0894: if (expression.requiresTypeFromContext()) {
0895: return false;
0896: }
0897:
0898: resultColumnType = getType();
0899:
0900: if (SanityManager.DEBUG) {
0901: if (!(resultColumnType != null)) {
0902: SanityManager.THROWASSERT("Type is null for column "
0903: + this );
0904: }
0905: }
0906:
0907: // Are we inserting/updating an XML column? If so, we always
0908: // return false so that normalization will occur. We have to
0909: // do this because there are different "kinds" of XML values
0910: // and we need to make sure they match--but we don't know
0911: // the "kind" until execution time. See the "normalize"
0912: // method in org.apache.derby.iapi.types.XML for more.
0913: if (resultColumnType.getTypeId().isXMLTypeId())
0914: return false;
0915:
0916: /* Are they the same type? */
0917: if (!resultColumnType.getTypeId().getSQLTypeName().equals(
0918: expressionType.getTypeId().getSQLTypeName())) {
0919: return false;
0920: }
0921:
0922: /* Are they the same precision? */
0923: if (resultColumnType.getPrecision() != expressionType
0924: .getPrecision()) {
0925: return false;
0926: }
0927:
0928: /* Are they the same scale? */
0929: if (resultColumnType.getScale() != expressionType.getScale()) {
0930: return false;
0931: }
0932:
0933: /* Are they the same width? */
0934: if (resultColumnType.getMaximumWidth() != expressionType
0935: .getMaximumWidth()) {
0936: return false;
0937: }
0938:
0939: /* Is the source nullable and the target non-nullable? */
0940: if ((!resultColumnType.isNullable())
0941: && expressionType.isNullable()) {
0942: return false;
0943: }
0944:
0945: return true;
0946: }
0947:
0948: boolean columnTypeAndLengthMatch(ResultColumn otherColumn)
0949: throws StandardException {
0950: DataTypeDescriptor resultColumnType;
0951: DataTypeDescriptor otherResultColumnType;
0952: ValueNode otherExpression = otherColumn.getExpression();
0953:
0954: resultColumnType = getType();
0955: otherResultColumnType = otherColumn.getType();
0956:
0957: if (SanityManager.DEBUG) {
0958: SanityManager.ASSERT(resultColumnType != null,
0959: "Type is null for column " + this );
0960: SanityManager.ASSERT(otherResultColumnType != null,
0961: "Type is null for column " + otherColumn);
0962: }
0963:
0964: /*
0965: ** We can never make any assumptions about
0966: ** parameters. So don't even bother in this
0967: ** case.
0968: */
0969: if ((otherExpression != null)
0970: && (otherExpression.requiresTypeFromContext())
0971: || (expression.requiresTypeFromContext())) {
0972: return false;
0973: }
0974:
0975: // Are we inserting/updating an XML column? If so, we always
0976: // return false so that normalization will occur. We have to
0977: // do this because there are different "kinds" of XML values
0978: // and we need to make sure they match--but we don't know
0979: // the "kind" until execution time. See the "normalize"
0980: // method in org.apache.derby.iapi.types.XML for more.
0981: if (resultColumnType.getTypeId().isXMLTypeId())
0982: return false;
0983:
0984: /* Are they the same type? */
0985: if (!resultColumnType.getTypeId().equals(
0986: otherResultColumnType.getTypeId())) {
0987: /* If the source is a constant of a different type then
0988: * we try to convert that constant to a constant of our
0989: * type. (The initial implementation only does the conversion
0990: * to string types because the most common problem is a char
0991: * constant with a varchar column.)
0992: * NOTE: We do not attempt any conversion here if the source
0993: * is a string type and the target is not or vice versa in
0994: * order to avoid problems with implicit varchar conversions.
0995: * Anyway, we will check if the "converted" constant has the
0996: * same type as the original constant. If not, then the conversion
0997: * happened. In that case, we will reuse the ConstantNode, for simplicity,
0998: * and reset the type to match the desired type.
0999: */
1000: if (otherExpression instanceof ConstantNode) {
1001: ConstantNode constant = (ConstantNode) otherColumn
1002: .getExpression();
1003: DataValueDescriptor oldValue = constant.getValue();
1004:
1005: DataValueDescriptor newValue = convertConstant(
1006: resultColumnType.getTypeId(), resultColumnType
1007: .getMaximumWidth(), oldValue);
1008:
1009: if ((oldValue != newValue)
1010: && (oldValue instanceof StringDataValue == newValue instanceof StringDataValue)) {
1011: constant.setValue(newValue);
1012: constant.setType(getTypeServices());
1013: otherColumn.bindResultColumnToExpression();
1014: otherResultColumnType = otherColumn.getType();
1015: }
1016: }
1017: if (!resultColumnType.getTypeId().equals(
1018: otherResultColumnType.getTypeId())) {
1019: return false;
1020: }
1021: }
1022:
1023: /* Are they the same precision? */
1024: if (resultColumnType.getPrecision() != otherResultColumnType
1025: .getPrecision()) {
1026: return false;
1027: }
1028:
1029: /* Are they the same scale? */
1030: if (resultColumnType.getScale() != otherResultColumnType
1031: .getScale()) {
1032: return false;
1033: }
1034:
1035: /* Are they the same width? */
1036: if (resultColumnType.getMaximumWidth() != otherResultColumnType
1037: .getMaximumWidth()) {
1038: return false;
1039: }
1040:
1041: /* Is the source nullable and the target non-nullable?
1042: * The source is nullable if it is nullable or if the target is generated
1043: * for an unmatched column in an insert with a column list.
1044: * This additional check is needed because when we generate any additional
1045: * source RCs for an insert with a column list the generated RCs for any
1046: * non-specified columns get the type info from the column. Thus,
1047: * for t1(non_nullable, nullable)
1048: * insert into t2 (nullable) values 1;
1049: * RCType.isNullable() returns false for the generated source RC for
1050: * non_nullable. In this case, we want to see it as
1051: */
1052: if ((!resultColumnType.isNullable())
1053: && (otherResultColumnType.isNullable() || otherColumn
1054: .isGeneratedForUnmatchedColumnInInsert())) {
1055: return false;
1056: }
1057:
1058: return true;
1059: }
1060:
1061: /**
1062: * Is this a generated column?
1063: *
1064: * @return Boolean - whether or not this column is a generated column.
1065: */
1066: public boolean isGenerated() {
1067: return (isGenerated == true);
1068: }
1069:
1070: /**
1071: * Is this columm generated for an unmatched column in an insert?
1072: *
1073: * @return Boolean - whether or not this columm was generated for an unmatched column in an insert.
1074: */
1075: public boolean isGeneratedForUnmatchedColumnInInsert() {
1076: return (isGeneratedForUnmatchedColumnInInsert == true);
1077: }
1078:
1079: /**
1080: * Mark this a columm as a generated column
1081: */
1082: public void markGenerated() {
1083: isGenerated = true;
1084: /* A generated column is a referenced column */
1085: isReferenced = true;
1086: }
1087:
1088: /**
1089: * Mark this a columm as generated for an unmatched column in an insert
1090: */
1091: public void markGeneratedForUnmatchedColumnInInsert() {
1092: isGeneratedForUnmatchedColumnInInsert = true;
1093: /* A generated column is a referenced column */
1094: isReferenced = true;
1095: }
1096:
1097: /**
1098: * Is this a referenced column?
1099: *
1100: * @return Boolean - whether or not this column is a referenced column.
1101: */
1102: public boolean isReferenced() {
1103: return isReferenced;
1104: }
1105:
1106: /**
1107: * Mark this column as a referenced column.
1108: */
1109: public void setReferenced() {
1110: isReferenced = true;
1111: }
1112:
1113: /**
1114: * Mark this column as a referenced column if it is already marked as referenced or if any result column in
1115: * its chain of virtual columns is marked as referenced.
1116: */
1117: void pullVirtualIsReferenced() {
1118: if (isReferenced())
1119: return;
1120:
1121: for (ValueNode expr = expression; expr != null
1122: && (expr instanceof VirtualColumnNode);) {
1123: VirtualColumnNode vcn = (VirtualColumnNode) expr;
1124: ResultColumn src = vcn.getSourceColumn();
1125: if (src.isReferenced()) {
1126: setReferenced();
1127: return;
1128: }
1129: expr = src.getExpression();
1130: }
1131: } // end of pullVirtualIsReferenced
1132:
1133: /**
1134: * Mark this column as an unreferenced column.
1135: */
1136: public void setUnreferenced() {
1137: isReferenced = false;
1138: }
1139:
1140: /**
1141: * Mark this RC and all RCs in the underlying
1142: * RC/VCN chain as referenced.
1143: */
1144: void markAllRCsInChainReferenced() {
1145: setReferenced();
1146:
1147: ValueNode vn = expression;
1148:
1149: while (vn instanceof VirtualColumnNode) {
1150: VirtualColumnNode vcn = (VirtualColumnNode) vn;
1151: ResultColumn rc = vcn.getSourceColumn();
1152: rc.setReferenced();
1153: vn = rc.getExpression();
1154: }
1155: }
1156:
1157: /**
1158: * Is this a redundant ResultColumn?
1159: *
1160: * @return Boolean - whether or not this RC is redundant.
1161: */
1162: public boolean isRedundant() {
1163: return isRedundant;
1164: }
1165:
1166: /**
1167: * Mark this ResultColumn as redundant.
1168: */
1169: public void setRedundant() {
1170: isRedundant = true;
1171: }
1172:
1173: /**
1174: * Mark this ResultColumn as a grouping column in the SELECT list
1175: */
1176: public void markAsGroupingColumn() {
1177: isGroupingColumn = true;
1178: }
1179:
1180: /**
1181: * Look for and reject ?/-?/+? parameter under this ResultColumn. This is
1182: * called for SELECT statements.
1183: *
1184: * @exception StandardException Thrown if a ?/-?/+? parameter was found
1185: * directly under this ResultColumn.
1186: */
1187:
1188: void rejectParameter() throws StandardException {
1189: if ((expression != null) && (expression.isParameterNode()))
1190: throw StandardException
1191: .newException(SQLState.LANG_PARAM_IN_SELECT_LIST);
1192: if ((expression != null)
1193: && (expression instanceof UnaryOperatorNode)
1194: && ((UnaryOperatorNode) expression)
1195: .isUnaryMinusOrPlusWithParameter())
1196: throw StandardException
1197: .newException(SQLState.LANG_PARAM_IN_SELECT_LIST);
1198: }
1199:
1200: /*
1201: ** The following methods implement the Comparable interface.
1202: */
1203: public int compareTo(Object other) {
1204: ResultColumn otherResultColumn = (ResultColumn) other;
1205:
1206: return this .getColumnPosition()
1207: - otherResultColumn.getColumnPosition();
1208: }
1209:
1210: /**
1211: * Mark this column as being updated by an update statemment.
1212: */
1213: void markUpdated() {
1214: updated = true;
1215: }
1216:
1217: /**
1218: * Mark this column as being updatable, so we can make sure it is in the
1219: * "for update" list of a positioned update.
1220: */
1221: void markUpdatableByCursor() {
1222: updatableByCursor = true;
1223: }
1224:
1225: /**
1226: * Tell whether this column is being updated.
1227: *
1228: * @return true means this column is being updated.
1229: */
1230: boolean updated() {
1231: return updated;
1232: }
1233:
1234: /**
1235: * Tell whether this column is updatable by a positioned update.
1236: *
1237: * @return true means this column is updatable
1238: */
1239: public boolean updatableByCursor() {
1240: return updatableByCursor;
1241: }
1242:
1243: /**
1244: * @see QueryTreeNode#disablePrivilegeCollection
1245: */
1246: public void disablePrivilegeCollection() {
1247: super .disablePrivilegeCollection();
1248: if (expression != null)
1249: expression.disablePrivilegeCollection();
1250: }
1251:
1252: /**
1253: * Make a copy of this ResultColumn in a new ResultColumn
1254: *
1255: * @return A new ResultColumn with the same contents as this one
1256: *
1257: * @exception StandardException Thrown on error
1258: */
1259: ResultColumn cloneMe() throws StandardException {
1260: ResultColumn newResultColumn;
1261: ValueNode cloneExpr;
1262:
1263: /* If expression is a ColumnReference, then we want to
1264: * have the RC's clone have a clone of the ColumnReference
1265: * for it's expression. This is for the special case of
1266: * cloning the SELECT list for the HAVING clause in the parser.
1267: * The SELECT generated for the HAVING needs its own copy
1268: * of the ColumnReferences.
1269: */
1270: if (expression instanceof ColumnReference) {
1271: cloneExpr = ((ColumnReference) expression).getClone();
1272: } else {
1273: cloneExpr = expression;
1274: }
1275:
1276: /* If a columnDescriptor exists, then we must propagate it */
1277: if (columnDescriptor != null) {
1278: newResultColumn = (ResultColumn) getNodeFactory().getNode(
1279: C_NodeTypes.RESULT_COLUMN, columnDescriptor,
1280: expression, getContextManager());
1281: newResultColumn.setExpression(cloneExpr);
1282: } else {
1283:
1284: newResultColumn = (ResultColumn) getNodeFactory().getNode(
1285: C_NodeTypes.RESULT_COLUMN, getName(), cloneExpr,
1286: getContextManager());
1287: }
1288:
1289: /* Set the VirtualColumnId and name in the new node */
1290: newResultColumn.setVirtualColumnId(getVirtualColumnId());
1291:
1292: /* Set the type and name information in the new node */
1293: newResultColumn.setName(getName());
1294: newResultColumn.setType(getTypeServices());
1295: newResultColumn.setNameGenerated(isNameGenerated());
1296:
1297: /* Set the "is generated for unmatched column in insert" status in the new node
1298: This if for bug 4194*/
1299: if (isGeneratedForUnmatchedColumnInInsert())
1300: newResultColumn.markGeneratedForUnmatchedColumnInInsert();
1301:
1302: /* Set the "is referenced" status in the new node */
1303: if (isReferenced())
1304: newResultColumn.setReferenced();
1305:
1306: /* Set the "updated" status in the new node */
1307: if (updated())
1308: newResultColumn.markUpdated();
1309:
1310: /* Setthe "updatable by cursor" status in the new node */
1311: if (updatableByCursor())
1312: newResultColumn.markUpdatableByCursor();
1313:
1314: if (isAutoincrementGenerated())
1315: newResultColumn.setAutoincrementGenerated();
1316:
1317: if (isAutoincrement())
1318: newResultColumn.setAutoincrement();
1319: if (isGroupingColumn())
1320: newResultColumn.markAsGroupingColumn();
1321: return newResultColumn;
1322: }
1323:
1324: /**
1325: * Get the maximum size of the column
1326: *
1327: * @return the max size
1328: */
1329: public int getMaximumColumnSize() {
1330: return dataTypeServices.getTypeId()
1331: .getApproximateLengthInBytes(dataTypeServices);
1332: }
1333:
1334: /**
1335: * Return the variant type for the underlying expression.
1336: * The variant type can be:
1337: * VARIANT - variant within a scan
1338: * (method calls and non-static field access)
1339: * SCAN_INVARIANT - invariant within a scan
1340: * (column references from outer tables)
1341: * QUERY_INVARIANT - invariant within the life of a query
1342: * CONSTANT - constant
1343: *
1344: * @return The variant type for the underlying expression.
1345: * @exception StandardException thrown on error
1346: */
1347: protected int getOrderableVariantType() throws StandardException {
1348: /*
1349: ** If the expression is VARIANT, then
1350: ** return VARIANT. Otherwise, we return
1351: ** CONSTANT. For result columns that are
1352: ** generating autoincrement values, the result
1353: ** is variant-- note that there is no expression
1354: ** associated with an autoincrement column in
1355: ** an insert statement.
1356: */
1357: int expType = ((expression != null) ? expression
1358: .getOrderableVariantType()
1359: : ((isAutoincrementGenerated()) ? Qualifier.VARIANT
1360: : Qualifier.CONSTANT));
1361:
1362: switch (expType) {
1363: case Qualifier.VARIANT:
1364: return Qualifier.VARIANT;
1365:
1366: case Qualifier.SCAN_INVARIANT:
1367: case Qualifier.QUERY_INVARIANT:
1368: return Qualifier.SCAN_INVARIANT;
1369:
1370: default:
1371: return Qualifier.CONSTANT;
1372: }
1373: }
1374:
1375: /**
1376: * Accept a visitor, and call v.visit()
1377: * on child nodes as necessary.
1378: *
1379: * @param v the visitor
1380: *
1381: * @exception StandardException on error
1382: */
1383: public Visitable accept(Visitor v) throws StandardException {
1384: Visitable returnNode = v.visit(this );
1385:
1386: if (v.skipChildren(this )) {
1387: return returnNode;
1388: }
1389:
1390: if (expression != null && !v.stopTraversal()) {
1391: expression = (ValueNode) expression.accept(v);
1392: }
1393: return returnNode;
1394: }
1395:
1396: /**
1397: * Set the nullability of this ResultColumn.
1398: */
1399: public void setNullability(boolean nullability) {
1400: dataTypeServices.setNullability(nullability);
1401: }
1402:
1403: /**
1404: * Is this column in this array of strings?
1405: *
1406: * @param list the array of column names to compare
1407: *
1408: * @return true/false
1409: */
1410: public boolean foundInList(String[] list) {
1411: return foundString(list, name);
1412: }
1413:
1414: /**
1415: * Verify that this RC is orderable.
1416: *
1417: * @exception StandardException Thrown on error
1418: */
1419: void verifyOrderable() throws StandardException {
1420: /*
1421: * Do not check to see if we can map user types
1422: * to built-in types. The ability to do so does
1423: * not mean that ordering will work. In fact,
1424: * as of version 2.0, ordering does not work on
1425: * user types.
1426: */
1427: if (!getTypeId().orderable(getClassFactory())) {
1428: throw StandardException
1429: .newException(
1430: SQLState.LANG_COLUMN_NOT_ORDERABLE_DURING_EXECUTION,
1431: getTypeId().getSQLTypeName());
1432: }
1433: }
1434:
1435: /**
1436: If this ResultColumn is bound to a column in a table
1437: get the column descriptor for the column in the table.
1438: Otherwise return null.
1439: */
1440: ColumnDescriptor getTableColumnDescriptor() {
1441: return columnDescriptor;
1442: }
1443:
1444: /**
1445: * Returns true if this result column is a placeholder for a generated
1446: * autoincrement value.
1447: */
1448: public boolean isAutoincrementGenerated() {
1449: return autoincrementGenerated;
1450: }
1451:
1452: public void setAutoincrementGenerated() {
1453: autoincrementGenerated = true;
1454: }
1455:
1456: public void resetAutoincrementGenerated() {
1457: autoincrementGenerated = false;
1458: }
1459:
1460: public boolean isAutoincrement() {
1461: return autoincrement;
1462: }
1463:
1464: public void setAutoincrement() {
1465: autoincrement = true;
1466: }
1467:
1468: public boolean isGroupingColumn() {
1469: return isGroupingColumn;
1470: }
1471:
1472: /**
1473: * @exception StandardException Thrown on error
1474: */
1475: private DataValueDescriptor convertConstant(TypeId toTypeId,
1476: int maxWidth, DataValueDescriptor constantValue)
1477: throws StandardException {
1478: int formatId = toTypeId.getTypeFormatId();
1479: DataValueFactory dvf = getDataValueFactory();
1480: switch (formatId) {
1481: default:
1482: case StoredFormatIds.CHAR_TYPE_ID:
1483: return constantValue;
1484:
1485: case StoredFormatIds.VARCHAR_TYPE_ID:
1486: case StoredFormatIds.NATIONAL_CHAR_TYPE_ID:
1487: case StoredFormatIds.NATIONAL_VARCHAR_TYPE_ID:
1488: String sourceValue = constantValue.getString();
1489: int sourceWidth = sourceValue.length();
1490: int posn;
1491:
1492: /*
1493: ** If the input is already the right length, no normalization is
1494: ** necessary - just return the source.
1495: **
1496: */
1497:
1498: if (sourceWidth <= maxWidth) {
1499: switch (formatId) {
1500: // For NCHAR we must pad the result, saves on normilization later if all
1501: // constants are of the correct size
1502: case StoredFormatIds.NATIONAL_CHAR_TYPE_ID:
1503:
1504: if (sourceWidth < maxWidth) {
1505: StringBuffer stringBuffer = new StringBuffer(
1506: sourceValue);
1507:
1508: int needed = maxWidth - sourceWidth;
1509: char blankArray[] = new char[needed];
1510: for (int i = 0; i < needed; i++)
1511: blankArray[i] = ' ';
1512: stringBuffer.append(blankArray, 0, maxWidth
1513: - sourceWidth);
1514: sourceValue = stringBuffer.toString();
1515: }
1516: return dvf.getNationalCharDataValue(sourceValue);
1517:
1518: case StoredFormatIds.NATIONAL_VARCHAR_TYPE_ID:
1519: return dvf.getNationalVarcharDataValue(sourceValue);
1520:
1521: case StoredFormatIds.VARCHAR_TYPE_ID:
1522: return dvf.getVarcharDataValue(sourceValue);
1523: }
1524: }
1525:
1526: /*
1527: ** Check whether any non-blank characters will be truncated.
1528: */
1529: for (posn = maxWidth; posn < sourceWidth; posn++) {
1530: if (sourceValue.charAt(posn) != ' ') {
1531: String typeName = null;
1532: switch (formatId) {
1533: case StoredFormatIds.NATIONAL_CHAR_TYPE_ID:
1534: typeName = TypeId.NATIONAL_CHAR_NAME;
1535: break;
1536:
1537: case StoredFormatIds.NATIONAL_VARCHAR_TYPE_ID:
1538: typeName = TypeId.NATIONAL_VARCHAR_NAME;
1539: break;
1540:
1541: case StoredFormatIds.VARCHAR_TYPE_ID:
1542: typeName = TypeId.VARCHAR_NAME;
1543: break;
1544: }
1545: throw StandardException.newException(
1546: SQLState.LANG_STRING_TRUNCATION, typeName,
1547: StringUtil.formatForPrint(sourceValue),
1548: String.valueOf(maxWidth));
1549: }
1550: }
1551:
1552: switch (formatId) {
1553: case StoredFormatIds.NATIONAL_CHAR_TYPE_ID:
1554: return dvf.getNationalCharDataValue(sourceValue
1555: .substring(0, maxWidth));
1556:
1557: case StoredFormatIds.NATIONAL_VARCHAR_TYPE_ID:
1558: return dvf.getNationalVarcharDataValue(sourceValue
1559: .substring(0, maxWidth));
1560:
1561: case StoredFormatIds.VARCHAR_TYPE_ID:
1562: return dvf.getVarcharDataValue(sourceValue.substring(0,
1563: maxWidth));
1564: }
1565:
1566: case StoredFormatIds.LONGVARCHAR_TYPE_ID:
1567: //No need to check widths here (unlike varchar), since no max width
1568: return dvf.getLongvarcharDataValue(constantValue
1569: .getString());
1570:
1571: case StoredFormatIds.NATIONAL_LONGVARCHAR_TYPE_ID:
1572: //No need to check widths here (unlike varchar), since no max width
1573: return dvf.getNationalLongvarcharDataValue(constantValue
1574: .getString());
1575:
1576: }
1577: }
1578:
1579: /**
1580: * Get the TypeId from this Node.
1581: *
1582: * @return The TypeId from this Node. This
1583: * may be null if the node isn't bound yet.
1584: */
1585: public TypeId getTypeId() throws StandardException {
1586: TypeId t = super .getTypeId();
1587: if (t == null) {
1588: if (expression != null) {
1589: DataTypeDescriptor dtd = getTypeServices();
1590: if (dtd != null)
1591: t = dtd.getTypeId();
1592: }
1593: }
1594: return t;
1595: } // end of getTypeId
1596:
1597: /**
1598: * Get the DataTypeServices from this Node.
1599: *
1600: * @return The DataTypeServices from this Node. This
1601: * may be null if the node isn't bound yet.
1602: */
1603: public DataTypeDescriptor getTypeServices()
1604: throws StandardException {
1605: DataTypeDescriptor dtd = super .getTypeServices();
1606: if (dtd == null && expression != null) {
1607: dtd = expression.getTypeServices();
1608: if (dtd != null)
1609: setType(dtd);
1610: }
1611: return dtd;
1612: } // end of getTypeServices
1613:
1614: public TableName getTableNameObject() {
1615: return null;
1616: }
1617:
1618: /* Get the wrapped reference if any */
1619: public ColumnReference getReference() {
1620: return reference;
1621: }
1622:
1623: /**
1624: * Get the source BaseColumnNode for this result column. The
1625: * BaseColumnNode cannot be found unless the ResultColumn is bound
1626: * and is a simple reference to a column in a BaseFromTable.
1627: *
1628: * @return a BaseColumnNode,
1629: * or null if a BaseColumnNode cannot be found
1630: */
1631: public BaseColumnNode getBaseColumnNode() {
1632: ValueNode vn = expression;
1633: while (true) {
1634: if (vn instanceof ResultColumn) {
1635: vn = ((ResultColumn) vn).expression;
1636: } else if (vn instanceof ColumnReference) {
1637: vn = ((ColumnReference) vn).getSource();
1638: } else if (vn instanceof VirtualColumnNode) {
1639: vn = ((VirtualColumnNode) vn).getSourceColumn();
1640: } else if (vn instanceof BaseColumnNode) {
1641: return (BaseColumnNode) vn;
1642: } else {
1643: return null;
1644: }
1645: }
1646: }
1647:
1648: /**
1649: * Search the tree beneath this ResultColumn until we find
1650: * the number of the table to which this RC points, and
1651: * return that table number. If we can't determine which
1652: * table this RC is for, then return -1.
1653: *
1654: * There are two places we can find the table number: 1) if
1655: * our expression is a ColumnReference, then we can get the
1656: * target table number from the ColumnReference and that's
1657: * it; 2) if expression is a VirtualColumnNode, then if
1658: * the VirtualColumnNode points to a FromBaseTable, we can
1659: * get that FBT's table number; otherwise, we walk the
1660: * VirtualColumnNode-ResultColumn chain and do a recursive
1661: * search.
1662: *
1663: * @return The number of the table to which this ResultColumn
1664: * points, or -1 if we can't determine that from where we are.
1665: */
1666: public int getTableNumber() throws StandardException {
1667: if (expression instanceof ColumnReference)
1668: return ((ColumnReference) expression).getTableNumber();
1669: else if (expression instanceof VirtualColumnNode) {
1670: VirtualColumnNode vcn = (VirtualColumnNode) expression;
1671:
1672: // If the VCN points to a FromBaseTable, just get that
1673: // table's number.
1674: if (vcn.getSourceResultSet() instanceof FromBaseTable) {
1675: return ((FromBaseTable) vcn.getSourceResultSet())
1676: .getTableNumber();
1677: }
1678:
1679: // Else recurse down the VCN.
1680: return vcn.getSourceColumn().getTableNumber();
1681: }
1682:
1683: // We can get here if expression has neither a column
1684: // reference nor a FromBaseTable beneath it--for example,
1685: // if it is of type BaseColumnNode.
1686: return -1;
1687: }
1688:
1689: public boolean isEquivalent(ValueNode o) throws StandardException {
1690: if (o.getNodeType() == getNodeType()) {
1691: ResultColumn other = (ResultColumn) o;
1692: if (expression != null) {
1693: return expression.isEquivalent(other.expression);
1694: }
1695: }
1696: return false;
1697: }
1698:
1699: }
|