/* 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.types;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
/**
*
*/
public enum QueryType {
INVALID (0), // used for parsing
NOOP (1),
SELECT (2),
INSERT (3),
UPDATE (4),
DELETE (5),
UPSERT (6);
QueryType(int val) {
assert (this.ordinal() == val) :
"Enum element " + this.name() +
" in position " + this.ordinal() +
" instead of position " + val;
}
public int getValue() {
return this.ordinal();
}
protected static final Map<Integer, QueryType> idx_lookup = new HashMap<Integer, QueryType>();
protected static final Map<String, QueryType> name_lookup = new HashMap<String, QueryType>();
static {
for (QueryType vt : EnumSet.allOf(QueryType.class)) {
QueryType.idx_lookup.put(vt.ordinal(), vt);
QueryType.name_lookup.put(vt.name().intern(), vt);
}
}
public static Map<Integer, QueryType> getIndexMap() {
return idx_lookup;
}
public static Map<String, QueryType> getNameMap() {
return name_lookup;
}
public static QueryType get(Integer idx) {
QueryType ret = QueryType.idx_lookup.get(idx);
return (ret == null ? QueryType.INVALID : ret);
}
public static QueryType get(String name) {
QueryType ret = QueryType.name_lookup.get(name.intern());
return (ret == null ? QueryType.INVALID : ret);
}
/**
* Determine what kind of SQL statement the given text represents.
* Don't use rocket science or anything, use the first word mostly.
* Code moved from deeper in the planner to here to be more general.
* @param stmt String of SQL
* @return Type of query
*/
public static QueryType getFromSQL(String stmt) {
// trim the front whitespace, substring to the first word and normalize
stmt = StringUtils.stripStart(stmt, null).substring(0, 6).toLowerCase();
// determine the type of the query
if (stmt.startsWith("insert")) {
return QueryType.INSERT;
}
else if (stmt.startsWith("update")) {
return QueryType.UPDATE;
}
else if (stmt.startsWith("delete") || stmt.startsWith("trunca")) {
return QueryType.DELETE;
}
else if (stmt.startsWith("select")) {
// This covers simple select statements as well as UNIONs and other set operations that are being used with default precedence
// as in "select ... from ... UNION select ... from ...;"
// Even if set operations are not currently supported, let them pass as "select" statements to let the parser sort them out.
return QueryType.SELECT;
}
else if (stmt.startsWith("upsert")) {
return QueryType.UPSERT;
}
else if (stmt.startsWith("(")) {
// There does not seem to be a need to support parenthesized DML statements, so assume a read-only statement.
// If that assumption is wrong, then it has probably gotten to the point that we want to drop this up-front
// logic in favor of relying on the full parser/planner to determine the cataloged query type and read-only-ness.
// Parenthesized query statements are typically complex set operations (UNIONS, etc.)
// requiring parenthesis to explicitly determine precedence,
// but they MAY be as simple as a needlessly parenthesized single select statement:
// "( select * from table );" is valid SQL.
// So, assume QueryType.SELECT.
// If set operations require their own QueryType in the future, that's probably another case
// motivating diving right in to the full parser/planner without this pre-check.
// We don't want to be re-implementing the parser here -- this has already gone far enough.
return QueryType.SELECT;
}
// else:
// All the known statements are handled above, so default to cataloging an invalid read-only statement
// and leave it to the parser/planner to more intelligently reject the statement as unsupported.
return QueryType.INVALID;
}
public boolean isReadOnly() {
return (this == SELECT) || (this == NOOP) || (this == INVALID);
}
}