/* This file is part of VoltDB.
* Copyright (C) 2008-2017 VoltDB Inc.
*
* 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 VoltDB. If not, see <http://www.gnu.org/licenses/>.
*/
package org.voltdb.planner;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.hsqldb_voltpatches.VoltXMLElement;
import org.voltdb.catalog.Column;
import org.voltdb.catalog.Database;
import org.voltdb.catalog.Table;
import org.voltdb.expressions.AbstractExpression;
import org.voltdb.expressions.TupleValueExpression;
import org.voltdb.plannodes.LimitPlanNode;
/**
*
*
*/
public class ParsedDeleteStmt extends AbstractParsedStmt {
/** Columns in the statements ORDER BY clause, if any */
private final List<ParsedColInfo> m_orderColumns = new ArrayList<>();
/** Limit plan node for this statement */
private LimitPlanNode m_limitPlanNode = null;
/**
* Class constructor
* @param paramValues
* @param db
*/
public ParsedDeleteStmt(String[] paramValues, Database db) {
super(paramValues, db);
}
/** Given XML for ORDER BY, add each column to m_orderColumns */
private void parseOrderColumns(VoltXMLElement orderColumnsXml) {
assert(m_orderColumns.size() == 0);
if (orderColumnsXml == null)
return;
for (VoltXMLElement orderColXml : orderColumnsXml.children) {
m_orderColumns.add(ParsedColInfo.fromOrderByXml(this, orderColXml));
}
}
@Override
void parse(VoltXMLElement stmtNode) {
assert(m_tableList.size() == 1);
VoltXMLElement limitXml = null;
VoltXMLElement offsetXml = null;
for (VoltXMLElement elem : stmtNode.children) {
if (elem.name.equalsIgnoreCase("ordercolumns")) {
parseOrderColumns(elem);
}
else if (elem.name.equalsIgnoreCase("limit")) {
limitXml = elem;
}
else if(elem.name.equalsIgnoreCase("offset")) {
offsetXml = elem;
}
}
m_limitPlanNode = limitPlanNodeFromXml(limitXml, offsetXml);
}
/** Returns TRUE if this statement had an ORDER BY clause */
@Override
public boolean hasOrderByColumns() {
return m_orderColumns.size() > 0;
}
/** Returns items in ORDER BY clause as a list of ParsedColInfo */
@Override
public List<ParsedColInfo> orderByColumns() {
return Collections.unmodifiableList(m_orderColumns);
}
/** Returns true if this statement has a LIMIT or OFFSET clause */
@Override
public boolean hasLimitOrOffset() {
return m_limitPlanNode != null;
}
/** Returns a copy of the limit node for this statement if any.
* The returned object is cloned, so it's suitable for connecting
* to an existing plan. */
public LimitPlanNode limitPlanNode() {
assert(m_limitPlanNode != null);
return new LimitPlanNode(m_limitPlanNode);
}
/**
* Returns true if the ORDER BY clause on this
* statement contains all the columns in the target table.
* Used to determine if rows are ordered deterministically.
* @return
*/
private boolean orderByCoversAllColumns() {
// SELECT statements do a check that is somewhat similar
// But we are restricted here to a single table with no
// table or column aliases allowed.
//
// Just build a set of all column names
// There could be non-trivial expressions in the order by clause
Set<String> allCols = new HashSet<>();
Table t = m_tableList.get(0);
for (Column c : t.getColumns()) {
allCols.add(c.getName());
}
for (ParsedColInfo col : orderByColumns()) {
AbstractExpression e = col.expression;
if (!(e instanceof TupleValueExpression)) {
continue;
}
TupleValueExpression tve = (TupleValueExpression)e;
allCols.remove(tve.getColumnName());
}
return allCols.isEmpty();
}
/** Returns true if the set of rows deleted by this statement
* is deterministic.
*/
public boolean sideEffectsAreDeterministic() {
if (! hasLimitOrOffset()) {
return true;
}
// Syntax requires LIMIT or OFFSET to have an ORDER BY
assert(hasOrderByColumns());
if (orderByColumnsCoverUniqueKeys()) {
return true;
}
if (orderByCoversAllColumns()) {
return true;
}
return false;
}
@Override
public String calculateContentDeterminismMessage() {
return null;
}
@Override
public boolean isDML() { return true; }
}