/** * Copyright (C) 2009-2013 FoundationDB, LLC * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.foundationdb.sql.optimizer.plan; import com.foundationdb.server.types.TInstance; import com.foundationdb.server.types.TPreptimeValue; import com.foundationdb.server.types.common.types.StringAttribute; import com.foundationdb.server.types.common.types.StringFactory; import com.foundationdb.server.types.common.types.TString; import com.foundationdb.server.types.value.ValueSource; import com.foundationdb.server.types.value.ValueSources; import com.foundationdb.sql.types.DataTypeDescriptor; import com.foundationdb.sql.parser.ValueNode; import com.foundationdb.util.AkibanAppender; /** An operand with a constant value. */ public class ConstantExpression extends BaseExpression { private Object value; public static ConstantExpression typedNull(DataTypeDescriptor sqlType, ValueNode sqlSource, TInstance type) { if (sqlType == null) { ValueSource nullSource = ValueSources.getNullSource(null); return new ConstantExpression(new TPreptimeValue(nullSource)); } if (type != null) { ValueSource nullSource = ValueSources.getNullSource(type); return new ConstantExpression((Object)null, sqlType, sqlSource, new TPreptimeValue(type, nullSource)); } else { return new ConstantExpression((Object)null, sqlType, sqlSource, new TPreptimeValue()); } } public ConstantExpression (Object value, DataTypeDescriptor sqlType, ValueNode sqlSource, TInstance type) { this (value, sqlType, sqlSource, getPreptimeValue(value, type)); } public ConstantExpression (Object value, DataTypeDescriptor sqlType, ValueNode sqlSource, TPreptimeValue preptimeValue) { super (sqlType, sqlSource, preptimeValue); this.value = value; } public ConstantExpression (Object value, TInstance type) { this(value, type.dataTypeDescriptor(), null, type); } public ConstantExpression(TPreptimeValue preptimeValue) { super (preptimeValue.type() == null ? null : preptimeValue.type().dataTypeDescriptor(), null, preptimeValue); } private static TPreptimeValue getPreptimeValue(Object value, TInstance type) { // For constant strings, reset the CollationID to NULL, // meaning they defer collation ordering to the other operand. if (type != null && type.typeClass() instanceof TString) { type = type.typeClass().instance( type.attribute(StringAttribute.MAX_LENGTH), type.attribute(StringAttribute.CHARSET), StringFactory.NULL_COLLATION_ID, type.nullability()); } return ValueSources.fromObject(value, type); } @Override public boolean isConstant() { return true; } public boolean isNullable() { if (value == null && getType() != null) { return getType().nullability(); } return false; } public Object getValue() { if (value == null) { ValueSource valueSource = getPreptimeValue().value(); if (valueSource == null || valueSource.isNull()) return null; value = ValueSources.toObject(valueSource); } return value; } @Override public boolean equals(Object obj) { if (!(obj instanceof ConstantExpression)) return false; ConstantExpression other = (ConstantExpression)obj; // Normalize to the value (from TPreptimeContext) ensureValueObject(this); ensureValueObject(other); return ((value == null) ? (other.value == null) : value.equals(other.value)); } @Override public int hashCode() { ensureValueObject(this); return (value == null) ? 0 : value.hashCode(); } private static void ensureValueObject(ConstantExpression constantExpression) { if (constantExpression.value == null) constantExpression.getValue(); } @Override public boolean accept(ExpressionVisitor v) { return v.visit(this); } @Override public ExpressionNode accept(ExpressionRewriteVisitor v) { return v.visit(this); } @Override public String toString() { ValueSource valueSource = getPreptimeValue().value(); if (valueSource == null || valueSource.isNull()) return "NULL"; StringBuilder sb = new StringBuilder(); getType().formatAsLiteral(valueSource, AkibanAppender.of(sb)); return sb.toString(); } @Override protected void deepCopy(DuplicateMap map) { super.deepCopy(map); // Do not copy object. } }