/* This file is part of VoltDB. * Copyright (C) 2008-2010 VoltDB L.L.C. * * VoltDB is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * VoltDB 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with VoltDB. If not, see <http://www.gnu.org/licenses/>. */ package org.voltdb.expressions; import org.json.JSONException; import org.json.JSONObject; import org.json.JSONString; import org.json.JSONStringer; import org.voltdb.VoltType; import org.voltdb.catalog.Database; import org.voltdb.types.ExpressionType; /** * */ public abstract class AbstractExpression implements JSONString, Cloneable { public enum Members { TYPE, LEFT, RIGHT, VALUE_TYPE, VALUE_SIZE; } protected String m_id; protected ExpressionType m_type; protected AbstractExpression m_left = null; protected AbstractExpression m_right = null; protected VoltType m_valueType = null; protected int m_valueSize = 0; // used by the planner internally (not needed in the EE) public boolean m_isJoiningClause = false; public AbstractExpression(ExpressionType type) { m_type = type; } public AbstractExpression(ExpressionType type, AbstractExpression left, AbstractExpression right) { this(type); m_left = left; m_right = right; } public AbstractExpression() { // This is needed for serialization } public void validate() throws Exception { // // Validate our children first // if (m_left != null) { m_left.validate(); } if (m_right != null) { m_right.validate(); } // // Expression Type // if (m_type == null) { throw new Exception("ERROR: The ExpressionType for '" + this + "' is NULL"); } else if (m_type == ExpressionType.INVALID) { throw new Exception("ERROR: The ExpressionType for '" + this + "' is " + m_type); // // Output Type // } else if (m_valueType == null) { throw new Exception("ERROR: The output VoltType for '" + this + "' is NULL"); } else if (m_valueType == VoltType.INVALID) { throw new Exception("ERROR: The output VoltType for '" + this + "' is " + m_valueType); } // // Since it is possible for an AbstractExpression to be stored with // any ExpressionType, we do a simple check to make sure that it is the right class // Class<?> check_class = m_type.getExpressionClass(); if (!check_class.isInstance(this)) { throw new Exception("ERROR: Expression '" + this + "' is class type '" + getClass().getSimpleName() + "' but needs to be '" + check_class.getSimpleName() + "'"); } } @Override public Object clone() throws CloneNotSupportedException { AbstractExpression clone = (AbstractExpression)super.clone(); // clone.m_id = m_id; // clone.m_isJoiningClause = m_isJoiningClause; // clone.m_type = m_type; // clone.m_valueType = m_valueType; // clone.m_valueSize = m_valueSize; if (m_left != null) { AbstractExpression left_clone = (AbstractExpression) m_left.clone(); clone.m_left = left_clone; } if (m_right != null) { AbstractExpression right_clone = (AbstractExpression) m_right.clone(); clone.m_right = right_clone; } return clone; } /** * @return the id */ public String getId() { return m_id; } public boolean isJoiningClause() { return m_isJoiningClause; } /** * @param id the id to set */ /*public void setId(String id) { m_id = id; }*/ /** * @return the type */ public ExpressionType getExpressionType() { return m_type; } /** * * @param type */ public void setExpressionType(ExpressionType type) { m_type = type; } /** * @return the left */ public AbstractExpression getLeft() { return m_left; } /** * @param left the left to set */ public void setLeft(AbstractExpression left) { m_left = left; } /** * @return the right */ public AbstractExpression getRight() { return m_right; } /** * @param right the right to set */ public void setRight(AbstractExpression right) { m_right = right; } /** * @return The type of this expression's value. */ public VoltType getValueType() { return m_valueType; } /** * @param type The type of this expression's value. */ public void setValueType(VoltType type) { m_valueType = type; } /** * @return The size of this expression's value in bytes. */ public int getValueSize() { return m_valueSize; } /** * @param size The size of this expression's value in bytes. */ public void setValueSize(int size) { assert (size >= 0); assert (size <= 10000000); m_valueSize = size; } @Override public String toString() { return "Expression: " + toJSONString(); } @Override public boolean equals(Object obj) { if (obj instanceof AbstractExpression == false) return false; AbstractExpression expr = (AbstractExpression) obj; // check that the presence, or lack thereof, of children is the same if ((expr.m_left == null) != (m_left == null)) return false; if ((expr.m_right == null) != (m_right == null)) return false; // check that the children identify themselves as the same if (expr.m_left != null) if (expr.m_left.equals(m_left) == false) return false; if (expr.m_right != null) if (expr.m_right.equals(m_right) == false) return false; if (m_type != expr.m_type) return false; if (m_valueSize != expr.m_valueSize) return false; if (m_isJoiningClause != expr.m_isJoiningClause) return false; if (m_valueType != expr.m_valueType) return false; // this abstract base class gets here if the children verify local members return true; } public String toJSONString() { JSONStringer stringer = new JSONStringer(); try { stringer.object(); toJSONString(stringer); stringer.endObject(); } catch (JSONException e) { e.printStackTrace(); return null; } return stringer.toString(); } public void toJSONString(JSONStringer stringer) throws JSONException { stringer.key(Members.TYPE.name()).value(m_type.toString()); stringer.key(Members.VALUE_TYPE.name()).value(m_valueType == null ? null : m_valueType.name()); stringer.key(Members.VALUE_SIZE.name()).value(m_valueSize); if (m_left != null) { assert (m_left instanceof JSONString); stringer.key(Members.LEFT.name()).value(m_left); } if (m_right != null) { assert (m_right instanceof JSONString); stringer.key(Members.RIGHT.name()).value(m_right); } } abstract protected void loadFromJSONObject(JSONObject obj, Database db) throws JSONException; public static AbstractExpression fromJSONObject(JSONObject obj, Database db) throws JSONException { ExpressionType type = ExpressionType.valueOf(obj.getString(Members.TYPE.name())); AbstractExpression expr; try { expr = type.getExpressionClass().newInstance(); } catch (InstantiationException e) { e.printStackTrace(); return null; } catch (IllegalAccessException e) { e.printStackTrace(); return null; } expr.m_type = type; expr.m_valueType = VoltType.typeFromString(obj.getString(Members.VALUE_TYPE.name())); expr.m_valueSize = obj.getInt(Members.VALUE_SIZE.name()); JSONObject leftObject = null; if (!obj.isNull(Members.LEFT.name())) { try { leftObject = obj.getJSONObject(Members.LEFT.name()); } catch (JSONException e) { //ok for it not to be there. } } if (leftObject != null) { expr.m_left = AbstractExpression.fromJSONObject(obj.getJSONObject(Members.LEFT.name()), db); } JSONObject rightObject = null; if (!obj.isNull(Members.RIGHT.name())) { try { rightObject = obj.getJSONObject(Members.RIGHT.name()); } catch (JSONException e) { //ok for it not to be there. } } if (rightObject != null) { expr.m_right = AbstractExpression.fromJSONObject(obj.getJSONObject(Members.RIGHT.name()), db); } expr.loadFromJSONObject(obj, db); return expr; } }