/** * 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.server.types.texpressions; import com.foundationdb.qp.operator.QueryBindings; import com.foundationdb.qp.operator.QueryContext; import com.foundationdb.qp.row.Row; import com.foundationdb.server.types.TInstance; import com.foundationdb.server.types.value.Value; import com.foundationdb.server.types.value.ValueSource; import com.foundationdb.server.types.value.ValueTarget; abstract class ContextualEvaluation<T> implements TEvaluatableExpression { @Override public void with(Row row) { } @Override public void with(QueryContext context) { } @Override public void with(QueryBindings bindings) { } @Override public ValueSource resultValue() { if (readyValue == null) throw new IllegalStateException("haven't evaluated since having seen a new context"); return readyValue; } @Override public void evaluate() { if (context == null) throw new IllegalStateException("no context given"); if (readyValue == null) { if (unreadyValue == null) { // first evaluation of this expression readyValue = new Value(underlyingType); } else { // readyValue is null, unreadyValue is not null. Means we've seen a QueryContext but have // not evaluated it. Set the readyValue to unreadyValue, as we've about to evaluate it. readyValue = unreadyValue; unreadyValue = null; } } evaluate(context, readyValue); } protected void setContext(T context) { if (unreadyValue == null) { // give unreadValue the readyValue, whatever it is (it could be null if we've never evaluated) // then set readyValue to null unreadyValue = readyValue; readyValue = null; } this.context = context; } protected abstract void evaluate(T context, ValueTarget target); protected ContextualEvaluation(TInstance underlyingType) { this.underlyingType = underlyingType; } // At most one of these will be non-null. If no QueryContext has been seen yet, they'll both be null. // Otherwise, unreadyValue means we've seen but not evaluated a QueryContext, and readyValue means we've // seen a QueryContext and evaluated it. private Value unreadyValue; private Value readyValue; private T context; private TInstance underlyingType; }