mirror of https://github.com/apache/cassandra
212 lines
5.9 KiB
Java
212 lines
5.9 KiB
Java
/*
|
|
*
|
|
* Licensed to the Apache Software Foundation (ASF) under one
|
|
* or more contributor license agreements. See the NOTICE file
|
|
* distributed with this work for additional information
|
|
* regarding copyright ownership. The ASF licenses this file
|
|
* to you under the Apache License, Version 2.0 (the
|
|
* "License"); you may not use this file except in compliance
|
|
* with the License. You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing,
|
|
* software distributed under the License is distributed on an
|
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
* KIND, either express or implied. See the License for the
|
|
* specific language governing permissions and limitations
|
|
* under the License.
|
|
*
|
|
*/
|
|
package org.apache.cassandra.cql;
|
|
|
|
import java.nio.ByteBuffer;
|
|
import java.util.List;
|
|
|
|
import org.apache.cassandra.db.marshal.AbstractType;
|
|
import org.apache.cassandra.db.marshal.AsciiType;
|
|
import org.apache.cassandra.db.marshal.FloatType;
|
|
import org.apache.cassandra.db.marshal.IntegerType;
|
|
import org.apache.cassandra.db.marshal.LexicalUUIDType;
|
|
import org.apache.cassandra.db.marshal.MarshalException;
|
|
import org.apache.cassandra.thrift.InvalidRequestException;
|
|
|
|
/** A term parsed from a CQL statement. */
|
|
public class Term
|
|
{
|
|
private final String text;
|
|
private final TermType type;
|
|
private Integer bindIndex = -1;
|
|
|
|
public Term(String text, TermType type)
|
|
{
|
|
this.text = text == null ? "" : text;
|
|
this.type = type;
|
|
}
|
|
|
|
/**
|
|
* Create new Term instance from a string, and an integer that corresponds
|
|
* with the token ID from CQLParser.
|
|
*
|
|
* @param text the text representation of the term.
|
|
* @param type the term's type as an integer token ID.
|
|
*/
|
|
public Term(String text, int type)
|
|
{
|
|
this(text == null ? "" : text, TermType.forInt(type));
|
|
}
|
|
|
|
public Term(long value, TermType type)
|
|
{
|
|
this(String.valueOf(value), type);
|
|
}
|
|
|
|
protected Term()
|
|
{
|
|
this("", TermType.STRING);
|
|
}
|
|
|
|
public Term(String text, int type, int index)
|
|
{
|
|
this(text, type);
|
|
this.bindIndex = index;
|
|
}
|
|
|
|
/**
|
|
* Returns the text parsed to create this term.
|
|
*
|
|
* @return the string term acquired from a CQL statement.
|
|
*/
|
|
public String getText()
|
|
{
|
|
return text;
|
|
}
|
|
|
|
/**
|
|
* Returns the typed value, serialized to a ByteBuffer according to a
|
|
* comparator/validator.
|
|
*
|
|
* @return a ByteBuffer of the value.
|
|
* @throws InvalidRequestException if unable to coerce the string to its type.
|
|
*/
|
|
public ByteBuffer getByteBuffer(AbstractType<?> validator, List<ByteBuffer> variables) throws InvalidRequestException
|
|
{
|
|
try
|
|
{
|
|
if (!isBindMarker()) return validator.fromString(text);
|
|
|
|
// must be a marker term so check for a CqlBindValue stored in the term
|
|
if (bindIndex == null)
|
|
throw new AssertionError("a marker Term was encountered with no index value");
|
|
|
|
return variables.get(bindIndex);
|
|
}
|
|
catch (MarshalException e)
|
|
{
|
|
throw new InvalidRequestException(e.getMessage());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns the typed value, serialized to a ByteBuffer.
|
|
*
|
|
* @return a ByteBuffer of the value.
|
|
* @throws InvalidRequestException if unable to coerce the string to its type.
|
|
*/
|
|
public ByteBuffer getByteBuffer() throws InvalidRequestException
|
|
{
|
|
switch (type)
|
|
{
|
|
case STRING:
|
|
return AsciiType.instance.fromString(text);
|
|
case INTEGER:
|
|
return IntegerType.instance.fromString(text);
|
|
case UUID:
|
|
// we specifically want the Lexical class here, not "UUIDType," because we're supposed to have
|
|
// a uuid-shaped string here, and UUIDType also accepts integer or date strings (and turns them into version 1 uuids).
|
|
return LexicalUUIDType.instance.fromString(text);
|
|
case FLOAT:
|
|
return FloatType.instance.fromString(text);
|
|
}
|
|
|
|
// FIXME: handle scenario that should never happen
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Obtain the term's type.
|
|
*
|
|
* @return the type
|
|
*/
|
|
public TermType getType()
|
|
{
|
|
return type;
|
|
}
|
|
|
|
public String toString()
|
|
{
|
|
return String.format("Term(%s, type=%s)", getText(), type);
|
|
}
|
|
|
|
public boolean isBindMarker()
|
|
{
|
|
return type==TermType.QMARK;
|
|
}
|
|
|
|
@Override
|
|
public int hashCode()
|
|
{
|
|
final int prime = 31;
|
|
int result = 1;
|
|
result = prime * result + ((text == null) ? 0 : text.hashCode());
|
|
result = prime * result + ((type == null) ? 0 : type.hashCode());
|
|
return result;
|
|
}
|
|
|
|
@Override
|
|
public boolean equals(Object obj)
|
|
{
|
|
if (this == obj)
|
|
return true;
|
|
if (obj == null)
|
|
return false;
|
|
if (getClass() != obj.getClass())
|
|
return false;
|
|
Term other = (Term) obj;
|
|
if (type==TermType.QMARK) return false; // markers are never equal
|
|
if (text == null)
|
|
{
|
|
if (other.text != null)
|
|
return false;
|
|
} else if (!text.equals(other.text))
|
|
return false;
|
|
if (type != other.type)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
enum TermType
|
|
{
|
|
STRING, INTEGER, UUID, FLOAT, QMARK;
|
|
|
|
static TermType forInt(int type)
|
|
{
|
|
if ((type == CqlParser.STRING_LITERAL) || (type == CqlParser.IDENT))
|
|
return STRING;
|
|
else if (type == CqlParser.INTEGER)
|
|
return INTEGER;
|
|
else if (type == CqlParser.UUID)
|
|
return UUID;
|
|
else if (type == CqlParser.FLOAT)
|
|
return FLOAT;
|
|
else if (type == CqlParser.QMARK)
|
|
return QMARK;
|
|
|
|
// FIXME: handled scenario that should never occur.
|
|
return null;
|
|
}
|
|
}
|