001: /*
002: * Copyright 2004-2008 H2 Group. Licensed under the H2 License, Version 1.0
003: * (http://h2database.com/html/license.html).
004: * Initial Developer: H2 Group
005: */
006: package org.h2.expression;
007:
008: import java.sql.SQLException;
009: import java.util.HashMap;
010:
011: import org.h2.command.Parser;
012: import org.h2.command.dml.Select;
013: import org.h2.constant.ErrorCode;
014: import org.h2.engine.Database;
015: import org.h2.engine.Session;
016: import org.h2.index.IndexCondition;
017: import org.h2.message.Message;
018: import org.h2.schema.Constant;
019: import org.h2.schema.Schema;
020: import org.h2.table.Column;
021: import org.h2.table.ColumnResolver;
022: import org.h2.table.Table;
023: import org.h2.table.TableFilter;
024: import org.h2.value.Value;
025: import org.h2.value.ValueBoolean;
026:
027: /**
028: * A expression that represents a column of a table or view.
029: */
030: public class ExpressionColumn extends Expression {
031: private Database database;
032: private String schemaName;
033: private String tableAlias;
034: private String columnName;
035: private ColumnResolver resolver;
036: private int queryLevel;
037: private Column column;
038: private boolean evaluatable;
039:
040: public ExpressionColumn(Database database, Column column) {
041: this .database = database;
042: this .column = column;
043: }
044:
045: public ExpressionColumn(Database database, String schemaName,
046: String tableAlias, String columnName) {
047: this .database = database;
048: this .schemaName = schemaName;
049: this .tableAlias = tableAlias;
050: this .columnName = columnName;
051: }
052:
053: public String getSQL() {
054: String sql;
055: if (column != null) {
056: sql = column.getSQL();
057: } else {
058: sql = columnName;
059: }
060: if (tableAlias != null) {
061: sql = Parser.quoteIdentifier(tableAlias) + "." + sql;
062: }
063: if (schemaName != null) {
064: sql = Parser.quoteIdentifier(schemaName) + "." + sql;
065: }
066: return sql;
067: }
068:
069: public TableFilter getTableFilter() {
070: return resolver == null ? null : resolver.getTableFilter();
071: }
072:
073: public void mapColumns(ColumnResolver resolver, int level)
074: throws SQLException {
075: if (tableAlias != null
076: && !tableAlias.equals(resolver.getTableAlias())) {
077: return;
078: }
079: if (schemaName != null
080: && !schemaName.equals(resolver.getSchemaName())) {
081: return;
082: }
083: Column[] columns = resolver.getColumns();
084: for (int i = 0; i < columns.length; i++) {
085: Column col = columns[i];
086: if (columnName.equals(col.getName())) {
087: mapColumn(resolver, col, level);
088: return;
089: }
090: }
091: columns = resolver.getSystemColumns();
092: for (int i = 0; columns != null && i < columns.length; i++) {
093: Column col = columns[i];
094: if (columnName.equals(col.getName())) {
095: mapColumn(resolver, col, level);
096: return;
097: }
098: }
099: }
100:
101: private void mapColumn(ColumnResolver resolver, Column col,
102: int level) throws SQLException {
103: if (this .resolver == null) {
104: queryLevel = level;
105: column = col;
106: this .resolver = resolver;
107: } else if (queryLevel == level && this .resolver != resolver) {
108: throw Message.getSQLException(
109: ErrorCode.AMBIGUOUS_COLUMN_NAME_1, columnName);
110: }
111: }
112:
113: public Expression optimize(Session session) throws SQLException {
114: if (resolver == null) {
115: Schema schema = session.getDatabase().findSchema(
116: tableAlias == null ? session.getCurrentSchemaName()
117: : tableAlias);
118: if (schema != null) {
119: Constant constant = schema.findConstant(columnName);
120: if (constant != null) {
121: return constant.getValue();
122: }
123: }
124: String name = columnName;
125: if (tableAlias != null) {
126: name = tableAlias + "." + name;
127: if (schemaName != null) {
128: name = schemaName + "." + name;
129: }
130: }
131: throw Message.getSQLException(ErrorCode.COLUMN_NOT_FOUND_1,
132: name);
133: }
134: return this ;
135: }
136:
137: public void updateAggregate(Session session) throws SQLException {
138: Value now = resolver.getValue(column);
139: Select select = resolver.getSelect();
140: if (select == null) {
141: throw Message.getSQLException(
142: ErrorCode.MUST_GROUP_BY_COLUMN_1, getSQL());
143: }
144: HashMap values = select.getCurrentGroup();
145: if (values == null) {
146: // this is a different level (the enclosing query)
147: return;
148: }
149: Value v = (Value) values.get(this );
150: if (v == null) {
151: values.put(this , now);
152: } else {
153: if (!database.areEqual(now, v)) {
154: throw Message.getSQLException(
155: ErrorCode.MUST_GROUP_BY_COLUMN_1, getSQL());
156: }
157: }
158: }
159:
160: public Value getValue(Session session) throws SQLException {
161: // TODO refactor: simplify check if really part of an aggregated value /
162: // detection of
163: // usage of non-grouped by columns without aggregate function
164: Select select = resolver.getSelect();
165: if (select != null) {
166: HashMap values = select.getCurrentGroup();
167: if (values != null) {
168: Value v = (Value) values.get(this );
169: if (v != null) {
170: return v;
171: }
172: }
173: }
174: Value value = resolver.getValue(column);
175: if (value == null) {
176: throw Message.getSQLException(
177: ErrorCode.MUST_GROUP_BY_COLUMN_1, getSQL());
178: }
179: return value;
180: }
181:
182: public int getType() {
183: return column.getType();
184: }
185:
186: public void setEvaluatable(TableFilter tableFilter, boolean b) {
187: if (resolver != null
188: && tableFilter == resolver.getTableFilter()) {
189: evaluatable = b;
190: }
191: }
192:
193: public Column getColumn() {
194: return column;
195: }
196:
197: public int getScale() {
198: return column.getScale();
199: }
200:
201: public long getPrecision() {
202: return column.getPrecision();
203: }
204:
205: public int getDisplaySize() {
206: return column.getDisplaySize();
207: }
208:
209: public String getOriginalColumnName() {
210: return columnName;
211: }
212:
213: public String getOriginalAliasName() {
214: return tableAlias;
215: }
216:
217: public String getColumnName() {
218: return columnName != null ? columnName : column.getName();
219: }
220:
221: public String getSchemaName() {
222: Table table = column.getTable();
223: return table == null ? null : table.getSchema().getName();
224: }
225:
226: public String getTableName() {
227: Table table = column.getTable();
228: return table == null ? null : table.getName();
229: }
230:
231: public String getAlias() {
232: return column.getName();
233: }
234:
235: public boolean isAutoIncrement() {
236: return column.getSequence() != null;
237: }
238:
239: public int getNullable() {
240: return column.getNullable() ? Column.NULLABLE
241: : Column.NOT_NULLABLE;
242: }
243:
244: public boolean isEverything(ExpressionVisitor visitor) {
245: switch (visitor.type) {
246: case ExpressionVisitor.OPTIMIZABLE_MIN_MAX_COUNT_ALL:
247: return false;
248: case ExpressionVisitor.READONLY:
249: case ExpressionVisitor.DETERMINISTIC:
250: return true;
251: case ExpressionVisitor.INDEPENDENT:
252: return this .queryLevel < visitor.queryLevel;
253: case ExpressionVisitor.EVALUATABLE:
254: // if the current value is known (evaluatable set)
255: // or if this columns belongs to a 'higher level' query and is
256: // therefore just a parameter
257: return evaluatable || visitor.queryLevel < this .queryLevel;
258: case ExpressionVisitor.SET_MAX_DATA_MODIFICATION_ID:
259: visitor.addDataModificationId(column.getTable()
260: .getMaxDataModificationId());
261: return true;
262: case ExpressionVisitor.NOT_FROM_RESOLVER:
263: return resolver != visitor.getResolver();
264: case ExpressionVisitor.GET_DEPENDENCIES:
265: visitor.addDependency(column.getTable());
266: return true;
267: default:
268: throw Message.getInternalError("type=" + visitor.type);
269: }
270: }
271:
272: public int getCost() {
273: return 2;
274: }
275:
276: public void createIndexConditions(Session session,
277: TableFilter filter) {
278: TableFilter tf = getTableFilter();
279: if (filter == tf && column.getType() == Value.BOOLEAN) {
280: IndexCondition cond = new IndexCondition(Comparison.EQUAL,
281: this , ValueExpression.get(ValueBoolean.get(true)));
282: filter.addIndexCondition(cond);
283: }
284: }
285:
286: public Expression getNotIfPossible(Session session) {
287: return new Comparison(session, Comparison.EQUAL, this ,
288: ValueExpression.get(ValueBoolean.get(false)));
289: }
290:
291: }
|