mirror of https://github.com/apache/cassandra
Improve CQL3 type validation
patch by slebresne; reviewed by iamaleksey for CASSANDRA-5198
This commit is contained in:
parent
4df6136d42
commit
a67f77922a
11
NEWS.txt
11
NEWS.txt
|
|
@ -8,6 +8,17 @@ upgrade, just in case you need to roll back to the previous version.
|
|||
(Cassandra version X + 1 will always be able to read data files created
|
||||
by version X, but the inverse is not necessarily the case.)
|
||||
|
||||
1.2.2
|
||||
=====
|
||||
|
||||
Upgrading
|
||||
---------
|
||||
- CQL3 type validation for constants has been fixed, which may require
|
||||
fixing queries that were relying on the previous loose validation. Please
|
||||
refer to the CQL3 documentation (http://cassandra.apache.org/doc/cql3/CQL.html)
|
||||
and in particular the changelog section for more details.
|
||||
|
||||
|
||||
1.2.1
|
||||
=====
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<link rel="StyleSheet" href="CQL.css" type="text/css" media="screen">
|
||||
|
||||
h1. Cassandra Query Language (CQL) v3.0.1
|
||||
h1. Cassandra Query Language (CQL) v3.0.2
|
||||
|
||||
|
||||
<span id="tableOfContents">
|
||||
|
|
@ -47,12 +47,15 @@ p. There is a second kind of identifiers called _quoted identifiers_ defined by
|
|||
|
||||
h3(#constants). Constants
|
||||
|
||||
CQL defines 4 kinds of _implicitly-typed constants_: strings, numbers, uuids and booleans:
|
||||
CQL defines the following kind of _constants_: strings, integers, floats, booleans, uuids and blobs:
|
||||
* A string constant is an arbitrary sequence of characters characters enclosed by single-quote(@'@). One can include a single-quote in a string by repeating it, e.g. @'It''s raining today'@. Those are not to be confused with quoted identifiers that use double-quotes.
|
||||
* Numeric constants are either integer constant defined by @'-'?[0-9]+@ or a float constant defined by @'-'?[0-9]+('.'[0-9]*)?([eE][+-]?[0-9+])?@.
|
||||
* A "UUID":http://en.wikipedia.org/wiki/Universally_unique_identifier constant is defined by @hex{8}-hex{4}-hex{4}-hex{4}-hex{12}@ where @hex@ is an hexadecimal character, e.g. @[0-9a-fA-F]@ and @{4}@ is the number of such characters.
|
||||
* An integer constant is defined by @'-'?[0-9]+@.
|
||||
* A float constant is defined by @'-'?[0-9]+('.'[0-9]*)?([eE][+-]?[0-9+])?@.
|
||||
* A boolean constant is either @true@ or @false@ up to case-insensitivity (i.e. @True@ is a valid boolean constant).
|
||||
* A "UUID":http://en.wikipedia.org/wiki/Universally_unique_identifier constant is defined by @hex{8}-hex{4}-hex{4}-hex{4}-hex{12}@ where @hex@ is an hexadecimal character, e.g. @[0-9a-fA-F]@ and @{4}@ is the number of such characters.
|
||||
* A blob constant is an hexadecimal number defined by @0[xX](hex)+@ where @hex@ is an hexadecimal character, e.g. @[0-9a-fA-F]@.
|
||||
|
||||
For how these constants are typed, see the "data types section":#types.
|
||||
|
||||
h3. Comments
|
||||
|
||||
|
|
@ -692,7 +695,7 @@ SELECT firstname, lastname FROM users WHERE birth_year = 1981 AND country = 'FR'
|
|||
|
||||
h2(#types). Data Types
|
||||
|
||||
CQL supports a rich set of native data types for columns defined in a table. On top of those native types, users can also provide custom types (through a JAVA class extending @AbstractType@ loadable by Cassandra). The syntax of types is thus:
|
||||
CQL supports a rich set of data types for columns defined in a table, including collection types. On top of those native and collection types, users can also provide custom types (through a JAVA class extending @AbstractType@ loadable by Cassandra). The syntax of types is thus:
|
||||
|
||||
bc(syntax)..
|
||||
<type> ::= <native-type>
|
||||
|
|
@ -721,25 +724,27 @@ bc(syntax)..
|
|||
| map '<' <native-type> ',' <native-type> '>'
|
||||
p. Note that the native types are keywords and as such are case-insensitive. They are however not reserved ones.
|
||||
|
||||
p. The following table gives additional informations on the native data types:
|
||||
p. The following table gives additional informations on the native data types, and on which kind of "constants":#constants each type supports:
|
||||
|
||||
|_. type |_. description|
|
||||
|@ascii@ |ASCII character string|
|
||||
|@bigint@ |64-bit signed long|
|
||||
|@blob@ |Arbitrary bytes (no validation)|
|
||||
|@boolean@ |true or false|
|
||||
|@counter@ |Counter column (64-bit signed value). See "Counters":#counters for details|
|
||||
|@decimal@ |Variable-precision decimal|
|
||||
|@double@ |64-bit IEEE-754 floating point|
|
||||
|@float@ |32-bit IEEE-754 floating point|
|
||||
|@inet@ |An IP address. It can be either 4 bytes long (IPv4) or 16 bytes long (IPv6)|
|
||||
|@int@ |32-bit signed int|
|
||||
|@text@ |UTF8 encoded string|
|
||||
|@timestamp@|A timestamp. See "Working with dates":#usingdates below for more information.|
|
||||
|@timeuuid@ |Type 1 UUID. This is generally used as a "conflict-free" timestamp. See "Working with @timeuuid@":#usingtimeuuid below.|
|
||||
|@uuid@ |Type 1 or type 4 UUID|
|
||||
|@varchar@ |UTF8 encoded string|
|
||||
|@varint@ |Arbitrary-precision integer|
|
||||
|_. type |_. constants supported|_. description|
|
||||
|@ascii@ | strings |ASCII character string|
|
||||
|@bigint@ | integers |64-bit signed long|
|
||||
|@blob@ | blobs |Arbitrary bytes (no validation)|
|
||||
|@boolean@ | booleans |true or false|
|
||||
|@counter@ | integers |Counter column (64-bit signed value). See "Counters":#counters for details|
|
||||
|@decimal@ | integers, floats |Variable-precision decimal|
|
||||
|@double@ | integers |64-bit IEEE-754 floating point|
|
||||
|@float@ | integers, floats |32-bit IEEE-754 floating point|
|
||||
|@inet@ | strings |An IP address. It can be either 4 bytes long (IPv4) or 16 bytes long (IPv6). There is no @inet@ constant, IP address should be inputed as strings|
|
||||
|@int@ | integers |32-bit signed int|
|
||||
|@text@ | strings |UTF8 encoded string|
|
||||
|@timestamp@| integers, strings |A timestamp. Strings constant are allow to input timestamps as dates, see "Working with dates":#usingdates below for more information.|
|
||||
|@timeuuid@ | uuids |Type 1 UUID. This is generally used as a "conflict-free" timestamp. See "Working with @timeuuid@":#usingtimeuuid below.|
|
||||
|@uuid@ | uuids |Type 1 or type 4 UUID|
|
||||
|@varchar@ | strings |UTF8 encoded string|
|
||||
|@varint@ | integers |Arbitrary-precision integer|
|
||||
|
||||
For more information on how to use the collection types, see the "Working with collections":#collections section below.
|
||||
|
||||
h3(#usingdates). Working with dates
|
||||
|
||||
|
|
@ -1000,6 +1005,10 @@ h2(#changes). Changes
|
|||
|
||||
The following describes the addition/changes brought for each version of CQL.
|
||||
|
||||
h3. 3.0.2
|
||||
|
||||
- Type validation for the "constants":#constants has been fixed. For instance, the implementation used to allow @'2'@ as a valid value for an @int@ column (interpreting it has the equivalent of @2@), or @42@ as a valid @blob@ value (in which case @42@ was interpreted as an hexadecimal representation of the blob). This is no longer the case, type validation of constants is now more strict. See the "data types":#dataTypes section for details on which constant is allowed for which type, but note that this let to the introduction of "blobs constants":#constants.
|
||||
|
||||
h3. 3.0.1
|
||||
|
||||
- "Date strings":#usingdates (and timestamps) are no longer accepted as valid @timeuuid@ values. Doing so was a bug in the sense that date string are not valid @timeuuid@, and it was thus resulting in "confusing behaviors":https://issues.apache.org/jira/browse/CASSANDRA-4936. However, the following new methods have been added to help working with @timeuuid@: @now@, @minTimeuuid@, @maxTimeuuid@ , @dateOf@ and @unixTimestampOf@. See the "section dedicated to these methods":#usingtimeuuid for more detail.
|
||||
|
|
|
|||
|
|
@ -22,13 +22,13 @@ import org.apache.cassandra.exceptions.InvalidRequestException;
|
|||
import org.apache.cassandra.exceptions.ConfigurationException;
|
||||
import org.apache.cassandra.exceptions.SyntaxException;
|
||||
|
||||
public interface ParsedType
|
||||
public interface CQL3Type
|
||||
{
|
||||
public boolean isCollection();
|
||||
public boolean isCounter();
|
||||
public AbstractType<?> getType();
|
||||
|
||||
public enum Native implements ParsedType
|
||||
public enum Native implements CQL3Type
|
||||
{
|
||||
ASCII (AsciiType.instance),
|
||||
BIGINT (LongType.instance),
|
||||
|
|
@ -68,15 +68,26 @@ public interface ParsedType
|
|||
{
|
||||
return this == COUNTER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return super.toString().toLowerCase();
|
||||
}
|
||||
}
|
||||
|
||||
public static class Custom implements ParsedType
|
||||
public static class Custom implements CQL3Type
|
||||
{
|
||||
private final AbstractType<?> type;
|
||||
|
||||
public Custom(AbstractType<?> type)
|
||||
{
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public Custom(String className) throws SyntaxException, ConfigurationException
|
||||
{
|
||||
this.type = TypeParser.parse(className);
|
||||
this(TypeParser.parse(className));
|
||||
}
|
||||
|
||||
public boolean isCollection()
|
||||
|
|
@ -93,18 +104,24 @@ public interface ParsedType
|
|||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "'" + type + "'";
|
||||
}
|
||||
}
|
||||
|
||||
public static class Collection implements ParsedType
|
||||
public static class Collection implements CQL3Type
|
||||
{
|
||||
CollectionType type;
|
||||
|
||||
private Collection(CollectionType type)
|
||||
public Collection(CollectionType type)
|
||||
{
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public static Collection map(ParsedType t1, ParsedType t2) throws InvalidRequestException
|
||||
public static Collection map(CQL3Type t1, CQL3Type t2) throws InvalidRequestException
|
||||
{
|
||||
if (t1.isCollection() || t2.isCollection())
|
||||
throw new InvalidRequestException("map type cannot contain another collection");
|
||||
|
|
@ -114,7 +131,7 @@ public interface ParsedType
|
|||
return new Collection(MapType.getInstance(t1.getType(), t2.getType()));
|
||||
}
|
||||
|
||||
public static Collection list(ParsedType t) throws InvalidRequestException
|
||||
public static Collection list(CQL3Type t) throws InvalidRequestException
|
||||
{
|
||||
if (t.isCollection())
|
||||
throw new InvalidRequestException("list type cannot contain another collection");
|
||||
|
|
@ -124,7 +141,7 @@ public interface ParsedType
|
|||
return new Collection(ListType.getInstance(t.getType()));
|
||||
}
|
||||
|
||||
public static Collection set(ParsedType t) throws InvalidRequestException
|
||||
public static Collection set(CQL3Type t) throws InvalidRequestException
|
||||
{
|
||||
if (t.isCollection())
|
||||
throw new InvalidRequestException("set type cannot contain another collection");
|
||||
|
|
@ -148,5 +165,21 @@ public interface ParsedType
|
|||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
switch (type.kind)
|
||||
{
|
||||
case LIST:
|
||||
return "list<" + ((ListType)type).elements.asCQL3Type() + ">";
|
||||
case SET:
|
||||
return "set<" + ((SetType)type).elements.asCQL3Type() + ">";
|
||||
case MAP:
|
||||
MapType mt = (MapType)type;
|
||||
return "set<" + mt.keys.asCQL3Type() + ", " + mt.values.asCQL3Type() + ">";
|
||||
}
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -662,8 +662,8 @@ map_literal returns [Map<Term, Term> value]
|
|||
;
|
||||
|
||||
finalTerm returns [Term term]
|
||||
: t=(STRING_LITERAL | UUID | INTEGER | FLOAT | K_TRUE | K_FALSE ) { $term = new Term($t.text, $t.type); }
|
||||
| f=(K_MIN_TIMEUUID | K_MAX_TIMEUUID | K_NOW) '(' (v=(STRING_LITERAL | INTEGER))? ')' { $term = new Term($f.text + "(" + ($v == null ? "" : $v.text) + ")", UUID); }
|
||||
: t=(STRING_LITERAL | UUID | INTEGER | FLOAT | BOOLEAN | HEXNUMBER ) { $term = new Term($t.text, $t.type); }
|
||||
| f=(K_MIN_TIMEUUID | K_MAX_TIMEUUID | K_NOW) '(' (v=(STRING_LITERAL | INTEGER))? ')' { $term = new Term($f.text + "(" + ($v == null ? "" : $v.text) + ")", Term.Type.UUID, true); }
|
||||
;
|
||||
|
||||
term returns [Term term]
|
||||
|
|
@ -741,15 +741,15 @@ property[PropertyDefinitions props]
|
|||
;
|
||||
|
||||
propertyValue returns [String str]
|
||||
: v=(STRING_LITERAL | IDENT | INTEGER | FLOAT | K_TRUE | K_FALSE) { $str = $v.text; }
|
||||
: v=(STRING_LITERAL | IDENT | INTEGER | FLOAT | BOOLEAN | HEXNUMBER) { $str = $v.text; }
|
||||
| u=unreserved_keyword { $str = u; }
|
||||
;
|
||||
|
||||
// Either a string or a list of terms
|
||||
tokenDefinition returns [Pair<String, List<Term>> tkdef]
|
||||
// Either a term or a list of terms
|
||||
tokenDefinition returns [Pair<Term, List<Term>> tkdef]
|
||||
: K_TOKEN { List<Term> l = new ArrayList<Term>(); }
|
||||
'(' t1=term { l.add(t1); } ( ',' tn=term { l.add(tn); } )* ')' { $tkdef = Pair.<String, List<Term>>create(null, l); }
|
||||
| t=STRING_LITERAL { $tkdef = Pair.<String, List<Term>>create($t.text, null); }
|
||||
'(' t1=term { l.add(t1); } ( ',' tn=term { l.add(tn); } )* ')' { $tkdef = Pair.<Term, List<Term>>create(null, l); }
|
||||
| t=term { $tkdef = Pair.<Term, List<Term>>create(t, null); }
|
||||
;
|
||||
|
||||
relation[List<Relation> clauses]
|
||||
|
|
@ -764,10 +764,10 @@ relation[List<Relation> clauses]
|
|||
}
|
||||
else
|
||||
{
|
||||
Term str = tkd.left == null ? null : new Term(tkd.left, Term.Type.STRING);
|
||||
Term tokenLitteral = tkd.left;
|
||||
for (int i = 0; i < l.size(); i++)
|
||||
{
|
||||
Term tt = str == null ? Term.tokenOf(tkd.right.get(i)) : str;
|
||||
Term tt = tokenLitteral == null ? Term.tokenOf(tkd.right.get(i)) : tokenLitteral;
|
||||
$clauses.add(new Relation(l.get(i), $type.text, tt, true));
|
||||
}
|
||||
}
|
||||
|
|
@ -776,13 +776,13 @@ relation[List<Relation> clauses]
|
|||
'(' f1=term { rel.addInValue(f1); } (',' fN=term { rel.addInValue(fN); } )* ')' { $clauses.add(rel); }
|
||||
;
|
||||
|
||||
comparatorType returns [ParsedType t]
|
||||
comparatorType returns [CQL3Type t]
|
||||
: c=native_type { $t = c; }
|
||||
| c=collection_type { $t = c; }
|
||||
| s=STRING_LITERAL
|
||||
{
|
||||
try {
|
||||
$t = new ParsedType.Custom($s.text);
|
||||
$t = new CQL3Type.Custom($s.text);
|
||||
} catch (SyntaxException e) {
|
||||
addRecognitionError("Cannot parse type " + $s.text + ": " + e.getMessage());
|
||||
} catch (ConfigurationException e) {
|
||||
|
|
@ -791,36 +791,36 @@ comparatorType returns [ParsedType t]
|
|||
}
|
||||
;
|
||||
|
||||
native_type returns [ParsedType t]
|
||||
: K_ASCII { $t = ParsedType.Native.ASCII; }
|
||||
| K_BIGINT { $t = ParsedType.Native.BIGINT; }
|
||||
| K_BLOB { $t = ParsedType.Native.BLOB; }
|
||||
| K_BOOLEAN { $t = ParsedType.Native.BOOLEAN; }
|
||||
| K_COUNTER { $t = ParsedType.Native.COUNTER; }
|
||||
| K_DECIMAL { $t = ParsedType.Native.DECIMAL; }
|
||||
| K_DOUBLE { $t = ParsedType.Native.DOUBLE; }
|
||||
| K_FLOAT { $t = ParsedType.Native.FLOAT; }
|
||||
| K_INET { $t = ParsedType.Native.INET;}
|
||||
| K_INT { $t = ParsedType.Native.INT; }
|
||||
| K_TEXT { $t = ParsedType.Native.TEXT; }
|
||||
| K_TIMESTAMP { $t = ParsedType.Native.TIMESTAMP; }
|
||||
| K_UUID { $t = ParsedType.Native.UUID; }
|
||||
| K_VARCHAR { $t = ParsedType.Native.VARCHAR; }
|
||||
| K_VARINT { $t = ParsedType.Native.VARINT; }
|
||||
| K_TIMEUUID { $t = ParsedType.Native.TIMEUUID; }
|
||||
native_type returns [CQL3Type t]
|
||||
: K_ASCII { $t = CQL3Type.Native.ASCII; }
|
||||
| K_BIGINT { $t = CQL3Type.Native.BIGINT; }
|
||||
| K_BLOB { $t = CQL3Type.Native.BLOB; }
|
||||
| K_BOOLEAN { $t = CQL3Type.Native.BOOLEAN; }
|
||||
| K_COUNTER { $t = CQL3Type.Native.COUNTER; }
|
||||
| K_DECIMAL { $t = CQL3Type.Native.DECIMAL; }
|
||||
| K_DOUBLE { $t = CQL3Type.Native.DOUBLE; }
|
||||
| K_FLOAT { $t = CQL3Type.Native.FLOAT; }
|
||||
| K_INET { $t = CQL3Type.Native.INET;}
|
||||
| K_INT { $t = CQL3Type.Native.INT; }
|
||||
| K_TEXT { $t = CQL3Type.Native.TEXT; }
|
||||
| K_TIMESTAMP { $t = CQL3Type.Native.TIMESTAMP; }
|
||||
| K_UUID { $t = CQL3Type.Native.UUID; }
|
||||
| K_VARCHAR { $t = CQL3Type.Native.VARCHAR; }
|
||||
| K_VARINT { $t = CQL3Type.Native.VARINT; }
|
||||
| K_TIMEUUID { $t = CQL3Type.Native.TIMEUUID; }
|
||||
;
|
||||
|
||||
collection_type returns [ParsedType pt]
|
||||
collection_type returns [CQL3Type pt]
|
||||
: K_MAP '<' t1=comparatorType ',' t2=comparatorType '>'
|
||||
{ try {
|
||||
// if we can't parse either t1 or t2, antlr will "recover" and we may have t1 or t2 null.
|
||||
if (t1 != null && t2 != null)
|
||||
$pt = ParsedType.Collection.map(t1, t2);
|
||||
$pt = CQL3Type.Collection.map(t1, t2);
|
||||
} catch (InvalidRequestException e) { addRecognitionError(e.getMessage()); } }
|
||||
| K_LIST '<' t=comparatorType '>'
|
||||
{ try { if (t != null) $pt = ParsedType.Collection.list(t); } catch (InvalidRequestException e) { addRecognitionError(e.getMessage()); } }
|
||||
{ try { if (t != null) $pt = CQL3Type.Collection.list(t); } catch (InvalidRequestException e) { addRecognitionError(e.getMessage()); } }
|
||||
| K_SET '<' t=comparatorType '>'
|
||||
{ try { if (t != null) $pt = ParsedType.Collection.set(t); } catch (InvalidRequestException e) { addRecognitionError(e.getMessage()); } }
|
||||
{ try { if (t != null) $pt = CQL3Type.Collection.set(t); } catch (InvalidRequestException e) { addRecognitionError(e.getMessage()); } }
|
||||
;
|
||||
|
||||
username
|
||||
|
|
@ -945,9 +945,6 @@ K_WRITETIME: W R I T E T I M E;
|
|||
K_MAP: M A P;
|
||||
K_LIST: L I S T;
|
||||
|
||||
K_TRUE: T R U E;
|
||||
K_FALSE: F A L S E;
|
||||
|
||||
K_MIN_TIMEUUID: M I N T I M E U U I D;
|
||||
K_MAX_TIMEUUID: M A X T I M E U U I D;
|
||||
K_NOW: N O W;
|
||||
|
|
@ -1027,10 +1024,21 @@ FLOAT
|
|||
| INTEGER '.' DIGIT* EXPONENT?
|
||||
;
|
||||
|
||||
/*
|
||||
* This has to be before IDENT so it takes precendence over it.
|
||||
*/
|
||||
BOOLEAN
|
||||
: T R U E | F A L S E
|
||||
;
|
||||
|
||||
IDENT
|
||||
: LETTER (LETTER | DIGIT | '_')*
|
||||
;
|
||||
|
||||
HEXNUMBER
|
||||
: '0' X HEX+
|
||||
;
|
||||
|
||||
UUID
|
||||
: HEX HEX HEX HEX HEX HEX HEX HEX '-'
|
||||
HEX HEX HEX HEX '-'
|
||||
|
|
|
|||
|
|
@ -20,8 +20,10 @@ package org.apache.cassandra.cql3;
|
|||
import java.nio.ByteBuffer;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.cassandra.db.marshal.AbstractType;
|
||||
import org.apache.cassandra.db.marshal.BytesType;
|
||||
import org.apache.cassandra.db.marshal.MarshalException;
|
||||
import org.apache.cassandra.exceptions.InvalidRequestException;
|
||||
|
||||
|
|
@ -30,11 +32,11 @@ public class Term
|
|||
{
|
||||
public enum Type
|
||||
{
|
||||
STRING, INTEGER, UUID, FLOAT, BOOLEAN, QMARK;
|
||||
STRING, INTEGER, UUID, FLOAT, BOOLEAN, HEX, QMARK;
|
||||
|
||||
static Type forInt(int type)
|
||||
{
|
||||
if ((type == CqlParser.STRING_LITERAL) || (type == CqlParser.IDENT))
|
||||
if (type == CqlParser.STRING_LITERAL)
|
||||
return STRING;
|
||||
else if (type == CqlParser.INTEGER)
|
||||
return INTEGER;
|
||||
|
|
@ -42,13 +44,14 @@ public class Term
|
|||
return UUID;
|
||||
else if (type == CqlParser.FLOAT)
|
||||
return FLOAT;
|
||||
else if (type == CqlParser.K_TRUE || type == CqlParser.K_FALSE)
|
||||
else if (type == CqlParser.BOOLEAN)
|
||||
return BOOLEAN;
|
||||
else if (type == CqlParser.HEXNUMBER)
|
||||
return HEX;
|
||||
else if (type == CqlParser.QMARK)
|
||||
return QMARK;
|
||||
|
||||
// FIXME: handled scenario that should never occur.
|
||||
return null;
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -57,17 +60,27 @@ public class Term
|
|||
public final int bindIndex;
|
||||
public final boolean isToken;
|
||||
|
||||
private Term(String text, Type type, int bindIndex, boolean isToken)
|
||||
// This is a hack for the timeuuid functions (minTimeuuid, maxTimeuuid, now) because instead of handling them as
|
||||
// true function we let the TimeUUID.fromString() method handle it. We should probably clean that up someday
|
||||
private final boolean skipTypeValidation;
|
||||
|
||||
private Term(String text, Type type, int bindIndex, boolean isToken, boolean skipTypeValidation)
|
||||
{
|
||||
this.text = text == null ? "" : text;
|
||||
this.text = text;
|
||||
this.type = type;
|
||||
this.bindIndex = bindIndex;
|
||||
this.isToken = isToken;
|
||||
this.skipTypeValidation = skipTypeValidation;
|
||||
}
|
||||
|
||||
public Term(String text, Type type, boolean skipTypeValidation)
|
||||
{
|
||||
this(text, type, -1, false, skipTypeValidation);
|
||||
}
|
||||
|
||||
public Term(String text, Type type)
|
||||
{
|
||||
this(text, type, -1, false);
|
||||
this(text, type, -1, false, false);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -89,12 +102,12 @@ public class Term
|
|||
|
||||
public Term(String text, int type, int index)
|
||||
{
|
||||
this(text, Type.forInt(type), index, false);
|
||||
this(text, Type.forInt(type), index, false, false);
|
||||
}
|
||||
|
||||
public static Term tokenOf(Term t)
|
||||
{
|
||||
return new Term(t.text, t.type, t.bindIndex, true);
|
||||
return new Term(t.text, t.type, t.bindIndex, true, false);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -119,7 +132,12 @@ public class Term
|
|||
try
|
||||
{
|
||||
if (!isBindMarker())
|
||||
{
|
||||
// BytesType doesn't want it's input prefixed by '0x'.
|
||||
if (type == Type.HEX && validator instanceof BytesType)
|
||||
return validator.fromString(text.substring(2));
|
||||
return validator.fromString(text);
|
||||
}
|
||||
|
||||
// must be a marker term so check for a CqlBindValue stored in the term
|
||||
if (bindIndex == -1)
|
||||
|
|
@ -138,6 +156,23 @@ public class Term
|
|||
}
|
||||
}
|
||||
|
||||
public void validateType(String identifier, AbstractType<?> validator) throws InvalidRequestException
|
||||
{
|
||||
if (skipTypeValidation)
|
||||
return;
|
||||
|
||||
Set<Type> supported = validator.supportedCQL3Constants();
|
||||
// Treat null specially as this mean "I don't have a supportedCQL3Type method"
|
||||
if (supported == null)
|
||||
return;
|
||||
|
||||
if (!supported.contains(type))
|
||||
{
|
||||
// TODO: Ideallly we'd keep the declared CQL3 type of columns and use that in the following message, instead of the AbstracType class name.
|
||||
throw new InvalidRequestException(String.format("Invalid %s constant for %s of type %s", type, identifier, validator.asCQL3Type()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain the term's type.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -112,10 +112,14 @@ public class ColumnOperation implements Operation
|
|||
cf.addCounter(new QueryPath(cf.metadata().cfName, null, builder.build()), val);
|
||||
}
|
||||
|
||||
public void addBoundNames(ColumnSpecification column, ColumnSpecification[] boundNames) throws InvalidRequestException
|
||||
public Operation validateAndAddBoundNames(ColumnSpecification column, ColumnSpecification[] boundNames) throws InvalidRequestException
|
||||
{
|
||||
value.validateType(column.name.toString(), column.type);
|
||||
|
||||
if (value.isBindMarker())
|
||||
boundNames[value.bindIndex] = column;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public List<Term> getValues()
|
||||
|
|
@ -123,7 +127,6 @@ public class ColumnOperation implements Operation
|
|||
return Collections.singletonList(value);
|
||||
}
|
||||
|
||||
|
||||
public boolean requiresRead(AbstractType<?> validator)
|
||||
{
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -285,26 +285,29 @@ public class ListOperation implements Operation
|
|||
cf.addColumn(params.makeTombstone(list.get(idx).right.name()));
|
||||
}
|
||||
|
||||
public void addBoundNames(ColumnSpecification column, ColumnSpecification[] boundNames) throws InvalidRequestException
|
||||
public Operation validateAndAddBoundNames(ColumnSpecification column, ColumnSpecification[] boundNames) throws InvalidRequestException
|
||||
{
|
||||
// Since the parser couldn't disambiguate between a 'list set by idx'
|
||||
// and a 'map put by key', we have to do it now.
|
||||
if (kind == Kind.SET_IDX && (column.type instanceof MapType))
|
||||
{
|
||||
assert values.size() == 2;
|
||||
MapOperation.Put(values.get(0), values.get(1)).addBoundNames(column, boundNames);
|
||||
return;
|
||||
return MapOperation.Put(values.get(0), values.get(1)).validateAndAddBoundNames(column, boundNames);
|
||||
}
|
||||
|
||||
if (!(column.type instanceof ListType))
|
||||
throw new InvalidRequestException(String.format("Invalid operation, %s is not of list type", column.name));
|
||||
throw new InvalidRequestException(String.format("Cannot apply list operation on column %s of type %s", column, column.type));
|
||||
|
||||
ListType lt = (ListType)column.type;
|
||||
if (kind == Kind.SET_IDX)
|
||||
{
|
||||
assert values.size() == 2;
|
||||
Term idx = values.get(0);
|
||||
idx.validateType("list index", Int32Type.instance);
|
||||
|
||||
Term value = values.get(1);
|
||||
value.validateType(column + " element", lt.elements);
|
||||
|
||||
if (idx.isBindMarker())
|
||||
boundNames[idx.bindIndex] = indexSpecOf(column);
|
||||
if (value.isBindMarker())
|
||||
|
|
@ -313,9 +316,13 @@ public class ListOperation implements Operation
|
|||
else
|
||||
{
|
||||
for (Term t : values)
|
||||
{
|
||||
t.validateType(column + " element", lt.elements);
|
||||
if (t.isBindMarker())
|
||||
boundNames[t.bindIndex] = column;
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public static ColumnSpecification indexSpecOf(ColumnSpecification column)
|
||||
|
|
|
|||
|
|
@ -129,21 +129,26 @@ public class MapOperation implements Operation
|
|||
cf.addColumn(params.makeTombstone(name));
|
||||
}
|
||||
|
||||
public void addBoundNames(ColumnSpecification column, ColumnSpecification[] boundNames) throws InvalidRequestException
|
||||
public Operation validateAndAddBoundNames(ColumnSpecification column, ColumnSpecification[] boundNames) throws InvalidRequestException
|
||||
{
|
||||
if (!(column.type instanceof MapType))
|
||||
throw new InvalidRequestException(String.format("Invalid operation, %s is not of map type", column.name));
|
||||
throw new InvalidRequestException(String.format("Cannot apply map operation on column %s of type %s", column, column.type));
|
||||
|
||||
MapType mt = (MapType)column.type;
|
||||
for (Map.Entry<Term, Term> entry : values.entrySet())
|
||||
{
|
||||
Term key = entry.getKey();
|
||||
key.validateType(column + " key", mt.keys);
|
||||
|
||||
Term value = entry.getValue();
|
||||
value.validateType(column + " value", mt.values);
|
||||
|
||||
if (key.isBindMarker())
|
||||
boundNames[key.bindIndex] = keySpecOf(column, mt);
|
||||
if (value.isBindMarker())
|
||||
boundNames[value.bindIndex] = valueSpecOf(column, mt);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public static ColumnSpecification keySpecOf(ColumnSpecification column, MapType type)
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ public interface Operation
|
|||
UpdateParameters params,
|
||||
List<Pair<ByteBuffer, IColumn>> list) throws InvalidRequestException;
|
||||
|
||||
public void addBoundNames(ColumnSpecification column, ColumnSpecification[] boundNames) throws InvalidRequestException;
|
||||
public Operation validateAndAddBoundNames(ColumnSpecification column, ColumnSpecification[] boundNames) throws InvalidRequestException;
|
||||
|
||||
public List<Term> getValues();
|
||||
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import org.apache.cassandra.db.ColumnFamily;
|
|||
import org.apache.cassandra.db.IColumn;
|
||||
import org.apache.cassandra.db.marshal.AbstractType;
|
||||
import org.apache.cassandra.db.marshal.CollectionType;
|
||||
import org.apache.cassandra.db.marshal.CounterColumnType;
|
||||
import org.apache.cassandra.db.marshal.ListType;
|
||||
import org.apache.cassandra.db.marshal.MapType;
|
||||
import org.apache.cassandra.db.marshal.SetType;
|
||||
|
|
@ -79,8 +80,6 @@ public class PreparedOperation implements Operation
|
|||
case SET:
|
||||
SetOperation.doSetFromPrepared(cf, builder, (SetType)validator, preparedValue, params);
|
||||
break;
|
||||
case PREPARED_PLUS:
|
||||
throw new InvalidRequestException("Unsupported syntax, cannot add to a prepared set");
|
||||
case PLUS_PREPARED:
|
||||
SetOperation.doAddFromPrepared(cf, builder, (SetType)validator, preparedValue, params);
|
||||
break;
|
||||
|
|
@ -95,13 +94,9 @@ public class PreparedOperation implements Operation
|
|||
case SET:
|
||||
MapOperation.doSetFromPrepared(cf, builder, (MapType)validator, preparedValue, params);
|
||||
break;
|
||||
case PREPARED_PLUS:
|
||||
throw new InvalidRequestException("Unsupported syntax, cannot put to a prepared map");
|
||||
case PLUS_PREPARED:
|
||||
MapOperation.doPutFromPrepared(cf, builder, (MapType)validator, preparedValue, params);
|
||||
break;
|
||||
case MINUS_PREPARED:
|
||||
throw new InvalidRequestException("Unsuppoted syntax, discard syntax for map not supported");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
@ -113,8 +108,6 @@ public class PreparedOperation implements Operation
|
|||
case SET:
|
||||
ColumnOperation.Set(preparedValue).execute(cf, builder, validator, params, null);
|
||||
break;
|
||||
case PREPARED_PLUS:
|
||||
throw new InvalidRequestException("Unsupported syntax for increment, must be of the form X = X + <value>");
|
||||
case PLUS_PREPARED:
|
||||
ColumnOperation.CounterInc(preparedValue).execute(cf, builder, validator, params, null);
|
||||
break;
|
||||
|
|
@ -125,10 +118,42 @@ public class PreparedOperation implements Operation
|
|||
}
|
||||
}
|
||||
|
||||
public void addBoundNames(ColumnSpecification column, ColumnSpecification[] boundNames) throws InvalidRequestException
|
||||
public Operation validateAndAddBoundNames(ColumnSpecification column, ColumnSpecification[] boundNames) throws InvalidRequestException
|
||||
{
|
||||
if (column.type instanceof CollectionType)
|
||||
{
|
||||
switch (kind)
|
||||
{
|
||||
case PREPARED_PLUS:
|
||||
if (column.type instanceof MapType)
|
||||
throw new InvalidRequestException("Unsupported syntax, cannot put to a prepared map");
|
||||
if (column.type instanceof SetType)
|
||||
throw new InvalidRequestException("Unsupported syntax, cannot add to a prepared set");
|
||||
break;
|
||||
case MINUS_PREPARED:
|
||||
if (column.type instanceof MapType)
|
||||
throw new InvalidRequestException("Unsuppoted syntax, discard syntax for map not supported");
|
||||
break;
|
||||
}
|
||||
switch (((CollectionType)column.type).kind)
|
||||
{
|
||||
}
|
||||
}
|
||||
else if (column.type instanceof CounterColumnType)
|
||||
{
|
||||
if (kind == Kind.PREPARED_PLUS)
|
||||
throw new InvalidRequestException("Unsupported syntax for increment, must be of the form X = X + <value>");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Any other operation than a set is invalid
|
||||
if (kind != Kind.SET)
|
||||
throw new InvalidRequestException(String.format("Invalid operation for %s of type %s", column, column.type));
|
||||
}
|
||||
|
||||
if (preparedValue.isBindMarker())
|
||||
boundNames[preparedValue.bindIndex] = column;
|
||||
return this;
|
||||
}
|
||||
|
||||
public List<Term> getValues()
|
||||
|
|
@ -142,7 +167,8 @@ public class PreparedOperation implements Operation
|
|||
return (validator instanceof ListType) && kind == Kind.MINUS_PREPARED;
|
||||
}
|
||||
|
||||
public boolean isPotentialCounterOperation() {
|
||||
public boolean isPotentialCounterOperation()
|
||||
{
|
||||
return kind == Kind.PLUS_PREPARED || kind == Kind.MINUS_PREPARED;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ import org.apache.cassandra.db.marshal.AbstractType;
|
|||
import org.apache.cassandra.db.marshal.CollectionType;
|
||||
import org.apache.cassandra.db.marshal.MarshalException;
|
||||
import org.apache.cassandra.db.marshal.SetType;
|
||||
import org.apache.cassandra.db.marshal.MapType;
|
||||
import org.apache.cassandra.exceptions.InvalidRequestException;
|
||||
import org.apache.cassandra.utils.ByteBufferUtil;
|
||||
import org.apache.cassandra.utils.Pair;
|
||||
|
|
@ -74,25 +75,6 @@ public class SetOperation implements Operation
|
|||
}
|
||||
}
|
||||
|
||||
public Operation maybeConvertToEmptyMapOperation()
|
||||
{
|
||||
// If it's not empty or a DISCARD, it's a proper invalid query, not
|
||||
// just the parser that hasn't been able to distinguish empty set from
|
||||
// empty map. However, we just this as it will be rejected later and
|
||||
// there is no point in duplicating validation
|
||||
if (!values.isEmpty())
|
||||
return this;
|
||||
|
||||
switch (kind)
|
||||
{
|
||||
case SET:
|
||||
return MapOperation.Set(Collections.<Term, Term>emptyMap());
|
||||
case ADD:
|
||||
return MapOperation.Put(Collections.<Term, Term>emptyMap());
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public static void doSetFromPrepared(ColumnFamily cf, ColumnNameBuilder builder, SetType validator, Term values, UpdateParameters params) throws InvalidRequestException
|
||||
{
|
||||
if (!values.isBindMarker())
|
||||
|
|
@ -166,11 +148,38 @@ public class SetOperation implements Operation
|
|||
}
|
||||
}
|
||||
|
||||
public void addBoundNames(ColumnSpecification column, ColumnSpecification[] boundNames) throws InvalidRequestException
|
||||
public Operation validateAndAddBoundNames(ColumnSpecification column, ColumnSpecification[] boundNames) throws InvalidRequestException
|
||||
{
|
||||
// On the parser side, we're unable to differentiate an empty map from an empty set for add and set operations.
|
||||
// Fix it now that we have the actual type.
|
||||
if (column.type instanceof MapType && values.isEmpty())
|
||||
return toEmptyMapOperation().validateAndAddBoundNames(column, boundNames);
|
||||
|
||||
if (!(column.type instanceof SetType))
|
||||
throw new InvalidRequestException(String.format("Cannot apply set operation on column %s of type %s", column, column.type));
|
||||
|
||||
AbstractType<?> valuesType = ((SetType)column.type).elements;
|
||||
|
||||
for (Term t : values)
|
||||
{
|
||||
t.validateType(column + " element", valuesType);
|
||||
|
||||
if (t.isBindMarker())
|
||||
boundNames[t.bindIndex] = column;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
private Operation toEmptyMapOperation()
|
||||
{
|
||||
switch (kind)
|
||||
{
|
||||
case SET:
|
||||
return MapOperation.Set(Collections.<Term, Term>emptyMap());
|
||||
case ADD:
|
||||
return MapOperation.Put(Collections.<Term, Term>emptyMap());
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public List<Term> getValues()
|
||||
|
|
|
|||
|
|
@ -43,12 +43,12 @@ public class AlterTableStatement extends SchemaAlteringStatement
|
|||
}
|
||||
|
||||
public final Type oType;
|
||||
public final ParsedType validator;
|
||||
public final CQL3Type validator;
|
||||
public final ColumnIdentifier columnName;
|
||||
private final CFPropDefs cfProps;
|
||||
private final Map<ColumnIdentifier, ColumnIdentifier> renames;
|
||||
|
||||
public AlterTableStatement(CFName name, Type type, ColumnIdentifier columnName, ParsedType validator, CFPropDefs cfProps, Map<ColumnIdentifier, ColumnIdentifier> renames)
|
||||
public AlterTableStatement(CFName name, Type type, ColumnIdentifier columnName, CQL3Type validator, CFPropDefs cfProps, Map<ColumnIdentifier, ColumnIdentifier> renames)
|
||||
{
|
||||
super(name);
|
||||
this.oType = type;
|
||||
|
|
|
|||
|
|
@ -142,7 +142,7 @@ public class CreateColumnFamilyStatement extends SchemaAlteringStatement
|
|||
|
||||
public static class RawStatement extends CFStatement
|
||||
{
|
||||
private final Map<ColumnIdentifier, ParsedType> definitions = new HashMap<ColumnIdentifier, ParsedType>();
|
||||
private final Map<ColumnIdentifier, CQL3Type> definitions = new HashMap<ColumnIdentifier, CQL3Type>();
|
||||
public final CFPropDefs properties = new CFPropDefs();
|
||||
|
||||
private final List<List<ColumnIdentifier>> keyAliases = new ArrayList<List<ColumnIdentifier>>();
|
||||
|
|
@ -178,10 +178,10 @@ public class CreateColumnFamilyStatement extends SchemaAlteringStatement
|
|||
stmt.setBoundTerms(getBoundsTerms());
|
||||
|
||||
Map<ByteBuffer, CollectionType> definedCollections = null;
|
||||
for (Map.Entry<ColumnIdentifier, ParsedType> entry : definitions.entrySet())
|
||||
for (Map.Entry<ColumnIdentifier, CQL3Type> entry : definitions.entrySet())
|
||||
{
|
||||
ColumnIdentifier id = entry.getKey();
|
||||
ParsedType pt = entry.getValue();
|
||||
CQL3Type pt = entry.getValue();
|
||||
if (pt.isCollection())
|
||||
{
|
||||
if (definedCollections == null)
|
||||
|
|
@ -350,7 +350,7 @@ public class CreateColumnFamilyStatement extends SchemaAlteringStatement
|
|||
return isReversed != null && isReversed ? ReversedType.getInstance(type) : type;
|
||||
}
|
||||
|
||||
public void addDefinition(ColumnIdentifier def, ParsedType type)
|
||||
public void addDefinition(ColumnIdentifier def, CQL3Type type)
|
||||
{
|
||||
definedNames.add(def);
|
||||
definitions.put(def, type);
|
||||
|
|
|
|||
|
|
@ -217,15 +217,19 @@ public class DeleteStatement extends ModificationStatement
|
|||
if (name.kind != CFDefinition.Name.Kind.COLUMN_METADATA && name.kind != CFDefinition.Name.Kind.VALUE_ALIAS)
|
||||
throw new InvalidRequestException(String.format("Invalid identifier %s for deletion (should not be a PRIMARY KEY part)", column));
|
||||
|
||||
if (column.key() != null)
|
||||
if (column.hasKey())
|
||||
{
|
||||
if (name.type instanceof ListType)
|
||||
{
|
||||
column.key().validateType("list index", Int32Type.instance);
|
||||
|
||||
if (column.key().isBindMarker())
|
||||
boundNames[column.key().bindIndex] = ListOperation.indexSpecOf(name);
|
||||
}
|
||||
else if (name.type instanceof MapType)
|
||||
{
|
||||
column.key().validateType("map key", ((MapType)name.type).keys);
|
||||
|
||||
if (column.key().isBindMarker())
|
||||
boundNames[column.key().bindIndex] = MapOperation.keySpecOf(name, (MapType)name.type);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -371,7 +371,7 @@ public class SelectStatement implements CQLStatement
|
|||
if (t == null)
|
||||
return p.getMinimumToken();
|
||||
|
||||
if (t.getType() == Term.Type.STRING && !t.isToken)
|
||||
if (!t.isToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
|
@ -1026,6 +1026,9 @@ public class SelectStatement implements CQLStatement
|
|||
}
|
||||
}
|
||||
|
||||
if (t.hasKey())
|
||||
throw new InvalidRequestException("Selecting a list/map element by index/key is not yet supported");
|
||||
|
||||
stmt.selectedNames.add(Pair.create(name, t));
|
||||
}
|
||||
}
|
||||
|
|
@ -1047,12 +1050,22 @@ public class SelectStatement implements CQLStatement
|
|||
if (rel.operator() == Relation.Type.IN)
|
||||
{
|
||||
for (Term value : rel.getInValues())
|
||||
{
|
||||
if (!rel.onToken || value.isToken)
|
||||
value.validateType(name.toString(), name.type);
|
||||
else
|
||||
value.validateType("token of " + name.toString(), StorageService.getPartitioner().getTokenValidator());
|
||||
if (value.isBindMarker())
|
||||
names[value.bindIndex] = name;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Term value = rel.getValue();
|
||||
if (!rel.onToken || value.isToken)
|
||||
value.validateType(name.toString(), name.type);
|
||||
else
|
||||
value.validateType("token of " + name.toString(), StorageService.getPartitioner().getTokenValidator());
|
||||
if (value.isBindMarker())
|
||||
names[value.bindIndex] = name;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -285,8 +285,7 @@ public class UpdateStatement extends ModificationStatement
|
|||
if (name == null)
|
||||
throw new InvalidRequestException(String.format("Unknown identifier %s", columnNames.get(i)));
|
||||
|
||||
Operation operation = columnOperations.get(i);
|
||||
operation.addBoundNames(name, boundNames);
|
||||
Operation operation = columnOperations.get(i).validateAndAddBoundNames(name, boundNames);
|
||||
|
||||
switch (name.kind)
|
||||
{
|
||||
|
|
@ -303,7 +302,7 @@ public class UpdateStatement extends ModificationStatement
|
|||
case COLUMN_METADATA:
|
||||
if (processedColumns.containsKey(name))
|
||||
throw new InvalidRequestException(String.format("Multiple definitions found for column %s", name));
|
||||
addNewOperation(name, operation);
|
||||
processedColumns.put(name, operation);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -317,7 +316,7 @@ public class UpdateStatement extends ModificationStatement
|
|||
if (name == null)
|
||||
throw new InvalidRequestException(String.format("Unknown identifier %s", entry.left));
|
||||
|
||||
Operation operation = entry.right;
|
||||
Operation operation = entry.right.validateAndAddBoundNames(name, boundNames);
|
||||
|
||||
switch (operation.getType())
|
||||
{
|
||||
|
|
@ -328,9 +327,6 @@ public class UpdateStatement extends ModificationStatement
|
|||
case LIST:
|
||||
case SET:
|
||||
case MAP:
|
||||
if (!name.type.isCollection())
|
||||
throw new InvalidRequestException("Cannot apply collection operation on column " + name + " with " + name.type + " type.");
|
||||
// Fallthrough on purpose
|
||||
case COLUMN:
|
||||
if (type == Type.COUNTER)
|
||||
throw new InvalidRequestException("Invalid non-counter operation on counter table.");
|
||||
|
|
@ -351,9 +347,7 @@ public class UpdateStatement extends ModificationStatement
|
|||
for (Operation otherOp : processedColumns.get(name))
|
||||
if (otherOp.getType() == Operation.Type.COLUMN)
|
||||
throw new InvalidRequestException(String.format("Multiple definitions found for column %s", name));
|
||||
|
||||
operation.addBoundNames(name, boundNames);
|
||||
addNewOperation(name, operation);
|
||||
processedColumns.put(name, operation);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -363,16 +357,6 @@ public class UpdateStatement extends ModificationStatement
|
|||
return new ParsedStatement.Prepared(this, Arrays.<ColumnSpecification>asList(boundNames));
|
||||
}
|
||||
|
||||
private void addNewOperation(CFDefinition.Name name, Operation operation)
|
||||
{
|
||||
// On the parser side, we're unable to differentiate an empty map from an empty set for add and set operations.
|
||||
// Fix it now that we have the actual type.
|
||||
if (operation.getType() == Operation.Type.SET && (name.type instanceof MapType))
|
||||
operation = ((SetOperation)operation).maybeConvertToEmptyMapOperation();
|
||||
|
||||
processedColumns.put(name, operation);
|
||||
}
|
||||
|
||||
public ParsedStatement.Prepared prepare() throws InvalidRequestException
|
||||
{
|
||||
ColumnSpecification[] names = new ColumnSpecification[getBoundsTerms()];
|
||||
|
|
@ -403,8 +387,11 @@ public class UpdateStatement extends ModificationStatement
|
|||
if (processed.containsKey(name.name))
|
||||
throw new InvalidRequestException(String.format("Multiple definitions found for PRIMARY KEY part %s", name));
|
||||
for (Term value : values)
|
||||
{
|
||||
value.validateType(name.toString(), name.type);
|
||||
if (value.isBindMarker())
|
||||
names[value.bindIndex] = name;
|
||||
}
|
||||
processed.put(name.name, values);
|
||||
break;
|
||||
case VALUE_ALIAS:
|
||||
|
|
|
|||
|
|
@ -205,7 +205,7 @@ public class SystemTable
|
|||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return String.format("{'%s': '%s'}",
|
||||
return String.format("{%s: 0x%s}",
|
||||
cfs.metadata.cfId,
|
||||
ByteBufferUtil.bytesToHex(ByteBuffer.wrap(out.getData(), 0, out.getLength())));
|
||||
}
|
||||
|
|
@ -263,7 +263,7 @@ public class SystemTable
|
|||
if (ep.equals(FBUtilities.getBroadcastAddress()))
|
||||
return;
|
||||
|
||||
String req = "INSERT INTO system.%s (peer, %s) VALUES ('%s', '%s')";
|
||||
String req = "INSERT INTO system.%s (peer, %s) VALUES ('%s', %s)";
|
||||
processInternal(String.format(req, PEERS_CF, columnName, ep.getHostAddress(), value));
|
||||
}
|
||||
|
||||
|
|
@ -571,7 +571,7 @@ public class SystemTable
|
|||
hostId = UUID.randomUUID();
|
||||
logger.warn("No host ID found, created {} (Note: This should happen exactly once per node).", hostId);
|
||||
|
||||
req = "INSERT INTO system.%s (key, host_id) VALUES ('%s', '%s')";
|
||||
req = "INSERT INTO system.%s (key, host_id) VALUES ('%s', %s)";
|
||||
processInternal(String.format(req, LOCAL_CF, LOCAL_KEY, hostId));
|
||||
return hostId;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,10 @@ import java.nio.ByteBuffer;
|
|||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.cassandra.cql3.CQL3Type;
|
||||
import org.apache.cassandra.cql3.Term;
|
||||
import org.apache.cassandra.exceptions.SyntaxException;
|
||||
import org.apache.cassandra.db.IColumn;
|
||||
import org.apache.cassandra.db.OnDiskAtom;
|
||||
|
|
@ -147,6 +150,18 @@ public abstract class AbstractType<T> implements Comparator<ByteBuffer>
|
|||
/* validate that the byte array is a valid sequence for the type we are supposed to be comparing */
|
||||
public abstract void validate(ByteBuffer bytes) throws MarshalException;
|
||||
|
||||
/* CQL3 types will actually override this, but we use a default for compatibility sake */
|
||||
public Set<Term.Type> supportedCQL3Constants()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/* Most of our internal type should override that. */
|
||||
public CQL3Type asCQL3Type()
|
||||
{
|
||||
return new CQL3Type.Custom(this);
|
||||
}
|
||||
|
||||
/** @deprecated use reverseComparator field instead */
|
||||
public Comparator<ByteBuffer> getReverseComparator()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -18,13 +18,19 @@
|
|||
package org.apache.cassandra.db.marshal;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.cassandra.cql.jdbc.JdbcAscii;
|
||||
import org.apache.cassandra.cql3.CQL3Type;
|
||||
import org.apache.cassandra.cql3.Term;
|
||||
|
||||
public class AsciiType extends AbstractType<String>
|
||||
{
|
||||
public static final AsciiType instance = new AsciiType();
|
||||
|
||||
private final Set<Term.Type> supportedCQL3Constants = EnumSet.of(Term.Type.STRING);
|
||||
|
||||
AsciiType() {} // singleton
|
||||
|
||||
public String getString(ByteBuffer bytes)
|
||||
|
|
@ -69,4 +75,14 @@ public class AsciiType extends AbstractType<String>
|
|||
throw new MarshalException("Invalid byte for ascii: " + Byte.toString(b));
|
||||
}
|
||||
}
|
||||
|
||||
public Set<Term.Type> supportedCQL3Constants()
|
||||
{
|
||||
return supportedCQL3Constants;
|
||||
}
|
||||
|
||||
public CQL3Type asCQL3Type()
|
||||
{
|
||||
return CQL3Type.Native.ASCII;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,13 +18,19 @@
|
|||
package org.apache.cassandra.db.marshal;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.cassandra.cql.jdbc.JdbcBoolean;
|
||||
import org.apache.cassandra.cql3.CQL3Type;
|
||||
import org.apache.cassandra.cql3.Term;
|
||||
|
||||
public class BooleanType extends AbstractType<Boolean>
|
||||
{
|
||||
public static final BooleanType instance = new BooleanType();
|
||||
|
||||
public final Set<Term.Type> supportedCQL3Constants = EnumSet.of(Term.Type.BOOLEAN);
|
||||
|
||||
BooleanType() {} // singleton
|
||||
|
||||
public Boolean compose(ByteBuffer bytes)
|
||||
|
|
@ -77,4 +83,14 @@ public class BooleanType extends AbstractType<Boolean>
|
|||
if (bytes.remaining() != 1 && bytes.remaining() != 0)
|
||||
throw new MarshalException(String.format("Expected 1 or 0 byte value (%d)", bytes.remaining()));
|
||||
}
|
||||
|
||||
public Set<Term.Type> supportedCQL3Constants()
|
||||
{
|
||||
return supportedCQL3Constants;
|
||||
}
|
||||
|
||||
public CQL3Type asCQL3Type()
|
||||
{
|
||||
return CQL3Type.Native.BOOLEAN;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,8 +18,12 @@
|
|||
package org.apache.cassandra.db.marshal;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.cassandra.cql.jdbc.JdbcBytes;
|
||||
import org.apache.cassandra.cql3.CQL3Type;
|
||||
import org.apache.cassandra.cql3.Term;
|
||||
import org.apache.cassandra.utils.ByteBufferUtil;
|
||||
import org.apache.cassandra.utils.Hex;
|
||||
|
||||
|
|
@ -27,6 +31,8 @@ public class BytesType extends AbstractType<ByteBuffer>
|
|||
{
|
||||
public static final BytesType instance = new BytesType();
|
||||
|
||||
private final Set<Term.Type> supportedCQL3Constants = EnumSet.of(Term.Type.HEX);
|
||||
|
||||
BytesType() {} // singleton
|
||||
|
||||
public ByteBuffer compose(ByteBuffer bytes)
|
||||
|
|
@ -81,4 +87,14 @@ public class BytesType extends AbstractType<ByteBuffer>
|
|||
// bytesType validate everything, so it is compatible with the former.
|
||||
return this == previous || previous == AsciiType.instance || previous == UTF8Type.instance;
|
||||
}
|
||||
|
||||
public Set<Term.Type> supportedCQL3Constants()
|
||||
{
|
||||
return supportedCQL3Constants;
|
||||
}
|
||||
|
||||
public CQL3Type asCQL3Type()
|
||||
{
|
||||
return CQL3Type.Native.BLOB;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ package org.apache.cassandra.db.marshal;
|
|||
import java.nio.ByteBuffer;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.cassandra.cql3.CQL3Type;
|
||||
import org.apache.cassandra.db.IColumn;
|
||||
import org.apache.cassandra.utils.ByteBufferUtil;
|
||||
import org.apache.cassandra.utils.Pair;
|
||||
|
|
@ -103,4 +104,10 @@ public abstract class CollectionType<T> extends AbstractType<T>
|
|||
}
|
||||
return (ByteBuffer)result.flip();
|
||||
}
|
||||
|
||||
|
||||
public CQL3Type asCQL3Type()
|
||||
{
|
||||
return new CQL3Type.Collection(this);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,11 @@
|
|||
package org.apache.cassandra.db.marshal;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.cassandra.cql3.CQL3Type;
|
||||
import org.apache.cassandra.cql3.Term;
|
||||
import org.apache.cassandra.db.*;
|
||||
import org.apache.cassandra.utils.ByteBufferUtil;
|
||||
|
||||
|
|
@ -26,6 +30,8 @@ public class CounterColumnType extends AbstractCommutativeType
|
|||
{
|
||||
public static final CounterColumnType instance = new CounterColumnType();
|
||||
|
||||
private final Set<Term.Type> supportedCQL3Constants = EnumSet.of(Term.Type.INTEGER);
|
||||
|
||||
CounterColumnType() {} // singleton
|
||||
|
||||
public int compare(ByteBuffer o1, ByteBuffer o2)
|
||||
|
|
@ -59,4 +65,14 @@ public class CounterColumnType extends AbstractCommutativeType
|
|||
if (bytes.remaining() != 8 && bytes.remaining() != 0)
|
||||
throw new MarshalException(String.format("Expected 8 or 0 byte long (%d)", bytes.remaining()));
|
||||
}
|
||||
|
||||
public Set<Term.Type> supportedCQL3Constants()
|
||||
{
|
||||
return supportedCQL3Constants;
|
||||
}
|
||||
|
||||
public CQL3Type asCQL3Type()
|
||||
{
|
||||
return CQL3Type.Native.COUNTER;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,8 +23,12 @@ import java.nio.ByteBuffer;
|
|||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.cassandra.cql.jdbc.JdbcDate;
|
||||
import org.apache.cassandra.cql3.CQL3Type;
|
||||
import org.apache.cassandra.cql3.Term;
|
||||
import org.apache.cassandra.utils.ByteBufferUtil;
|
||||
import org.apache.commons.lang.time.DateUtils;
|
||||
|
||||
|
|
@ -33,9 +37,10 @@ public class DateType extends AbstractType<Date>
|
|||
public static final DateType instance = new DateType();
|
||||
|
||||
static final String DEFAULT_FORMAT = iso8601Patterns[3];
|
||||
|
||||
static final SimpleDateFormat FORMATTER = new SimpleDateFormat(DEFAULT_FORMAT);
|
||||
|
||||
private final Set<Term.Type> supportedCQL3Constants = EnumSet.of(Term.Type.STRING, Term.Type.INTEGER);
|
||||
|
||||
DateType() {} // singleton
|
||||
|
||||
public Date compose(ByteBuffer bytes)
|
||||
|
|
@ -124,4 +129,14 @@ public class DateType extends AbstractType<Date>
|
|||
if (bytes.remaining() != 8 && bytes.remaining() != 0)
|
||||
throw new MarshalException(String.format("Expected 8 or 0 byte long for date (%d)", bytes.remaining()));
|
||||
}
|
||||
|
||||
public Set<Term.Type> supportedCQL3Constants()
|
||||
{
|
||||
return supportedCQL3Constants;
|
||||
}
|
||||
|
||||
public CQL3Type asCQL3Type()
|
||||
{
|
||||
return CQL3Type.Native.TIMESTAMP;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,14 +19,20 @@ package org.apache.cassandra.db.marshal;
|
|||
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.cassandra.cql.jdbc.JdbcDecimal;
|
||||
import org.apache.cassandra.cql3.CQL3Type;
|
||||
import org.apache.cassandra.cql3.Term;
|
||||
import org.apache.cassandra.utils.ByteBufferUtil;
|
||||
|
||||
public class DecimalType extends AbstractType<BigDecimal>
|
||||
{
|
||||
public static final DecimalType instance = new DecimalType();
|
||||
|
||||
private final Set<Term.Type> supportedCQL3Constants = EnumSet.of(Term.Type.INTEGER, Term.Type.FLOAT);
|
||||
|
||||
DecimalType() {} // singleton
|
||||
|
||||
public int compare(ByteBuffer bb0, ByteBuffer bb1)
|
||||
|
|
@ -85,4 +91,14 @@ public class DecimalType extends AbstractType<BigDecimal>
|
|||
{
|
||||
// no useful check for invalid decimals.
|
||||
}
|
||||
|
||||
public Set<Term.Type> supportedCQL3Constants()
|
||||
{
|
||||
return supportedCQL3Constants;
|
||||
}
|
||||
|
||||
public CQL3Type asCQL3Type()
|
||||
{
|
||||
return CQL3Type.Native.DECIMAL;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,14 +18,20 @@
|
|||
package org.apache.cassandra.db.marshal;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.cassandra.cql.jdbc.JdbcDouble;
|
||||
import org.apache.cassandra.cql3.CQL3Type;
|
||||
import org.apache.cassandra.cql3.Term;
|
||||
import org.apache.cassandra.utils.ByteBufferUtil;
|
||||
|
||||
public class DoubleType extends AbstractType<Double>
|
||||
{
|
||||
public static final DoubleType instance = new DoubleType();
|
||||
|
||||
private final Set<Term.Type> supportedCQL3Constants = EnumSet.of(Term.Type.INTEGER, Term.Type.FLOAT);
|
||||
|
||||
DoubleType() {} // singleton
|
||||
|
||||
public Double compose(ByteBuffer bytes)
|
||||
|
|
@ -88,4 +94,14 @@ public class DoubleType extends AbstractType<Double>
|
|||
if (bytes.remaining() != 8 && bytes.remaining() != 0)
|
||||
throw new MarshalException(String.format("Expected 8 or 0 byte value for a double (%d)", bytes.remaining()));
|
||||
}
|
||||
|
||||
public Set<Term.Type> supportedCQL3Constants()
|
||||
{
|
||||
return supportedCQL3Constants;
|
||||
}
|
||||
|
||||
public CQL3Type asCQL3Type()
|
||||
{
|
||||
return CQL3Type.Native.DOUBLE;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,8 +18,12 @@
|
|||
package org.apache.cassandra.db.marshal;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.cassandra.cql.jdbc.JdbcFloat;
|
||||
import org.apache.cassandra.cql3.CQL3Type;
|
||||
import org.apache.cassandra.cql3.Term;
|
||||
import org.apache.cassandra.utils.ByteBufferUtil;
|
||||
|
||||
|
||||
|
|
@ -27,6 +31,8 @@ public class FloatType extends AbstractType<Float>
|
|||
{
|
||||
public static final FloatType instance = new FloatType();
|
||||
|
||||
private final Set<Term.Type> supportedCQL3Constants = EnumSet.of(Term.Type.INTEGER, Term.Type.FLOAT);
|
||||
|
||||
FloatType() {} // singleton
|
||||
|
||||
public Float compose(ByteBuffer bytes)
|
||||
|
|
@ -87,4 +93,14 @@ public class FloatType extends AbstractType<Float>
|
|||
if (bytes.remaining() != 4 && bytes.remaining() != 0)
|
||||
throw new MarshalException(String.format("Expected 4 or 0 byte value for a float (%d)", bytes.remaining()));
|
||||
}
|
||||
|
||||
public Set<Term.Type> supportedCQL3Constants()
|
||||
{
|
||||
return supportedCQL3Constants;
|
||||
}
|
||||
|
||||
public CQL3Type asCQL3Type()
|
||||
{
|
||||
return CQL3Type.Native.FLOAT;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,14 +20,20 @@ package org.apache.cassandra.db.marshal;
|
|||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.cassandra.cql.jdbc.JdbcInetAddress;
|
||||
import org.apache.cassandra.cql3.CQL3Type;
|
||||
import org.apache.cassandra.cql3.Term;
|
||||
import org.apache.cassandra.utils.ByteBufferUtil;
|
||||
|
||||
public class InetAddressType extends AbstractType<InetAddress>
|
||||
{
|
||||
public static final InetAddressType instance = new InetAddressType();
|
||||
|
||||
private final Set<Term.Type> supportedCQL3Constants = EnumSet.of(Term.Type.STRING);
|
||||
|
||||
InetAddressType() {} // singleton
|
||||
|
||||
public InetAddress compose(ByteBuffer bytes)
|
||||
|
|
@ -81,4 +87,14 @@ public class InetAddressType extends AbstractType<InetAddress>
|
|||
throw new MarshalException(String.format("Expected 4 or 16 byte inetaddress; got %s", ByteBufferUtil.bytesToHex(bytes)));
|
||||
}
|
||||
}
|
||||
|
||||
public Set<Term.Type> supportedCQL3Constants()
|
||||
{
|
||||
return supportedCQL3Constants;
|
||||
}
|
||||
|
||||
public CQL3Type asCQL3Type()
|
||||
{
|
||||
return CQL3Type.Native.INET;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,14 +18,20 @@
|
|||
package org.apache.cassandra.db.marshal;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.cassandra.cql.jdbc.JdbcInt32;
|
||||
import org.apache.cassandra.cql3.CQL3Type;
|
||||
import org.apache.cassandra.cql3.Term;
|
||||
import org.apache.cassandra.utils.ByteBufferUtil;
|
||||
|
||||
public class Int32Type extends AbstractType<Integer>
|
||||
{
|
||||
public static final Int32Type instance = new Int32Type();
|
||||
|
||||
private final Set<Term.Type> supportedCQL3Constants = EnumSet.of(Term.Type.INTEGER);
|
||||
|
||||
Int32Type() {} // singleton
|
||||
|
||||
public Integer compose(ByteBuffer bytes)
|
||||
|
|
@ -95,4 +101,13 @@ public class Int32Type extends AbstractType<Integer>
|
|||
throw new MarshalException(String.format("Expected 4 or 0 byte int (%d)", bytes.remaining()));
|
||||
}
|
||||
|
||||
public Set<Term.Type> supportedCQL3Constants()
|
||||
{
|
||||
return supportedCQL3Constants;
|
||||
}
|
||||
|
||||
public CQL3Type asCQL3Type()
|
||||
{
|
||||
return CQL3Type.Native.INT;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,14 +19,20 @@ package org.apache.cassandra.db.marshal;
|
|||
|
||||
import java.math.BigInteger;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.cassandra.cql.jdbc.JdbcInteger;
|
||||
import org.apache.cassandra.cql3.CQL3Type;
|
||||
import org.apache.cassandra.cql3.Term;
|
||||
import org.apache.cassandra.utils.ByteBufferUtil;
|
||||
|
||||
public final class IntegerType extends AbstractType<BigInteger>
|
||||
{
|
||||
public static final IntegerType instance = new IntegerType();
|
||||
|
||||
private final Set<Term.Type> supportedCQL3Constants = EnumSet.of(Term.Type.INTEGER);
|
||||
|
||||
private static int findMostSignificantByte(ByteBuffer bytes)
|
||||
{
|
||||
int len = bytes.remaining() - 1;
|
||||
|
|
@ -152,4 +158,14 @@ public final class IntegerType extends AbstractType<BigInteger>
|
|||
{
|
||||
// no invalid integers.
|
||||
}
|
||||
|
||||
public Set<Term.Type> supportedCQL3Constants()
|
||||
{
|
||||
return supportedCQL3Constants;
|
||||
}
|
||||
|
||||
public CQL3Type asCQL3Type()
|
||||
{
|
||||
return CQL3Type.Native.VARINT;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,9 +18,12 @@
|
|||
package org.apache.cassandra.db.marshal;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.apache.cassandra.cql.jdbc.JdbcLexicalUUID;
|
||||
import org.apache.cassandra.cql3.Term;
|
||||
import org.apache.cassandra.utils.ByteBufferUtil;
|
||||
import org.apache.cassandra.utils.UUIDGen;
|
||||
|
||||
|
|
@ -28,6 +31,8 @@ public class LexicalUUIDType extends AbstractType<UUID>
|
|||
{
|
||||
public static final LexicalUUIDType instance = new LexicalUUIDType();
|
||||
|
||||
private final Set<Term.Type> supportedCQL3Constants = EnumSet.of(Term.Type.UUID);
|
||||
|
||||
LexicalUUIDType() {} // singleton
|
||||
|
||||
public UUID compose(ByteBuffer bytes)
|
||||
|
|
@ -88,4 +93,9 @@ public class LexicalUUIDType extends AbstractType<UUID>
|
|||
throw new MarshalException(String.format("LexicalUUID should be 16 or 0 bytes (%d)", bytes.remaining()));
|
||||
// not sure what the version should be for this.
|
||||
}
|
||||
|
||||
public Set<Term.Type> supportedCQL3Constants()
|
||||
{
|
||||
return supportedCQL3Constants;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,14 +18,20 @@
|
|||
package org.apache.cassandra.db.marshal;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.cassandra.cql.jdbc.JdbcLong;
|
||||
import org.apache.cassandra.cql3.CQL3Type;
|
||||
import org.apache.cassandra.cql3.Term;
|
||||
import org.apache.cassandra.utils.ByteBufferUtil;
|
||||
|
||||
public class LongType extends AbstractType<Long>
|
||||
{
|
||||
public static final LongType instance = new LongType();
|
||||
|
||||
private final Set<Term.Type> supportedCQL3Constants = EnumSet.of(Term.Type.INTEGER);
|
||||
|
||||
LongType() {} // singleton
|
||||
|
||||
public Long compose(ByteBuffer bytes)
|
||||
|
|
@ -94,4 +100,14 @@ public class LongType extends AbstractType<Long>
|
|||
if (bytes.remaining() != 8 && bytes.remaining() != 0)
|
||||
throw new MarshalException(String.format("Expected 8 or 0 byte long (%d)", bytes.remaining()));
|
||||
}
|
||||
|
||||
public Set<Term.Type> supportedCQL3Constants()
|
||||
{
|
||||
return supportedCQL3Constants;
|
||||
}
|
||||
|
||||
public CQL3Type asCQL3Type()
|
||||
{
|
||||
return CQL3Type.Native.BIGINT;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,11 +18,15 @@
|
|||
package org.apache.cassandra.db.marshal;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.apache.cassandra.cql.jdbc.JdbcTimeUUID;
|
||||
import org.apache.cassandra.cql3.CQL3Type;
|
||||
import org.apache.cassandra.cql3.Term;
|
||||
import org.apache.cassandra.utils.ByteBufferUtil;
|
||||
import org.apache.cassandra.utils.UUIDGen;
|
||||
|
||||
|
|
@ -33,6 +37,8 @@ public class TimeUUIDType extends AbstractType<UUID>
|
|||
static final Pattern regexPattern = Pattern.compile("[A-Fa-f0-9]{8}\\-[A-Fa-f0-9]{4}\\-[A-Fa-f0-9]{4}\\-[A-Fa-f0-9]{4}\\-[A-Fa-f0-9]{12}");
|
||||
static final Pattern functionPattern = Pattern.compile("(\\w+)\\((.*)\\)");
|
||||
|
||||
private final Set<Term.Type> supportedCQL3Constants = EnumSet.of(Term.Type.UUID);
|
||||
|
||||
TimeUUIDType() {} // singleton
|
||||
|
||||
public UUID compose(ByteBuffer bytes)
|
||||
|
|
@ -209,4 +215,14 @@ public class TimeUUIDType extends AbstractType<UUID>
|
|||
throw new MarshalException("Invalid version for TimeUUID type.");
|
||||
}
|
||||
}
|
||||
|
||||
public Set<Term.Type> supportedCQL3Constants()
|
||||
{
|
||||
return supportedCQL3Constants;
|
||||
}
|
||||
|
||||
public CQL3Type asCQL3Type()
|
||||
{
|
||||
return CQL3Type.Native.TIMEUUID;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,13 +18,19 @@
|
|||
package org.apache.cassandra.db.marshal;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.cassandra.cql.jdbc.JdbcUTF8;
|
||||
import org.apache.cassandra.cql3.CQL3Type;
|
||||
import org.apache.cassandra.cql3.Term;
|
||||
|
||||
public class UTF8Type extends AbstractType<String>
|
||||
{
|
||||
public static final UTF8Type instance = new UTF8Type();
|
||||
|
||||
private final Set<Term.Type> supportedCQL3Constants = EnumSet.of(Term.Type.STRING);
|
||||
|
||||
UTF8Type() {} // singleton
|
||||
|
||||
public String compose(ByteBuffer bytes)
|
||||
|
|
@ -190,4 +196,14 @@ public class UTF8Type extends AbstractType<String>
|
|||
// comparison
|
||||
return this == previous || previous == AsciiType.instance;
|
||||
}
|
||||
|
||||
public Set<Term.Type> supportedCQL3Constants()
|
||||
{
|
||||
return supportedCQL3Constants;
|
||||
}
|
||||
|
||||
public CQL3Type asCQL3Type()
|
||||
{
|
||||
return CQL3Type.Native.TEXT;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,9 +20,13 @@ package org.apache.cassandra.db.marshal;
|
|||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.text.ParseException;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.apache.cassandra.cql.jdbc.JdbcUUID;
|
||||
import org.apache.cassandra.cql3.CQL3Type;
|
||||
import org.apache.cassandra.cql3.Term;
|
||||
import org.apache.cassandra.utils.ByteBufferUtil;
|
||||
import org.apache.cassandra.utils.FBUtilities;
|
||||
import org.apache.cassandra.utils.UUIDGen;
|
||||
|
|
@ -44,6 +48,8 @@ public class UUIDType extends AbstractType<UUID>
|
|||
{
|
||||
public static final UUIDType instance = new UUIDType();
|
||||
|
||||
private final Set<Term.Type> supportedCQL3Constants = EnumSet.of(Term.Type.UUID);
|
||||
|
||||
UUIDType()
|
||||
{
|
||||
}
|
||||
|
|
@ -242,4 +248,14 @@ public class UUIDType extends AbstractType<UUID>
|
|||
|
||||
return idBytes;
|
||||
}
|
||||
|
||||
public Set<Term.Type> supportedCQL3Constants()
|
||||
{
|
||||
return supportedCQL3Constants;
|
||||
}
|
||||
|
||||
public CQL3Type asCQL3Type()
|
||||
{
|
||||
return CQL3Type.Native.UUID;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@ import org.apache.cassandra.utils.ByteBufferUtil;
|
|||
import org.apache.commons.lang.ArrayUtils;
|
||||
|
||||
import org.apache.cassandra.db.DecoratedKey;
|
||||
import org.apache.cassandra.db.marshal.AbstractType;
|
||||
import org.apache.cassandra.db.marshal.BytesType;
|
||||
import org.apache.cassandra.exceptions.ConfigurationException;
|
||||
import org.apache.cassandra.service.StorageService;
|
||||
import org.apache.cassandra.utils.FBUtilities;
|
||||
|
|
@ -215,4 +217,9 @@ public abstract class AbstractByteOrderedPartitioner extends AbstractPartitioner
|
|||
|
||||
return allTokens;
|
||||
}
|
||||
|
||||
public AbstractType<?> getTokenValidator()
|
||||
{
|
||||
return BytesType.instance;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
|
||||
import org.apache.cassandra.db.DecoratedKey;
|
||||
import org.apache.cassandra.db.marshal.AbstractType;
|
||||
|
||||
public interface IPartitioner<T extends Token>
|
||||
{
|
||||
|
|
@ -84,5 +85,7 @@ public interface IPartitioner<T extends Token>
|
|||
*/
|
||||
public Map<Token, Float> describeOwnership(List<Token> sortedTokens);
|
||||
|
||||
public AbstractType<?> getTokenValidator();
|
||||
|
||||
public <R extends RingPosition> R minValue(Class<R> klass);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -79,4 +79,9 @@ public class LocalPartitioner extends AbstractPartitioner<LocalToken>
|
|||
{
|
||||
return Collections.singletonMap((Token)getMinimumToken(), new Float(1.0));
|
||||
}
|
||||
|
||||
public AbstractType<?> getTokenValidator()
|
||||
{
|
||||
return comparator;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
|
||||
import org.apache.cassandra.db.DecoratedKey;
|
||||
import org.apache.cassandra.db.marshal.AbstractType;
|
||||
import org.apache.cassandra.db.marshal.LongType;
|
||||
import org.apache.cassandra.exceptions.ConfigurationException;
|
||||
import org.apache.cassandra.utils.ByteBufferUtil;
|
||||
import org.apache.cassandra.utils.FBUtilities;
|
||||
|
|
@ -186,4 +188,9 @@ public class Murmur3Partitioner extends AbstractPartitioner<LongToken>
|
|||
return new LongToken(Long.valueOf(string));
|
||||
}
|
||||
};
|
||||
|
||||
public AbstractType<?> getTokenValidator()
|
||||
{
|
||||
return LongType.instance;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,6 +24,8 @@ import java.util.*;
|
|||
|
||||
import org.apache.cassandra.config.*;
|
||||
import org.apache.cassandra.db.DecoratedKey;
|
||||
import org.apache.cassandra.db.marshal.AbstractType;
|
||||
import org.apache.cassandra.db.marshal.UTF8Type;
|
||||
import org.apache.cassandra.exceptions.ConfigurationException;
|
||||
import org.apache.cassandra.gms.VersionedValue;
|
||||
import org.apache.cassandra.service.StorageService;
|
||||
|
|
@ -208,4 +210,9 @@ public class OrderPreservingPartitioner extends AbstractPartitioner<StringToken>
|
|||
|
||||
return allTokens;
|
||||
}
|
||||
|
||||
public AbstractType<?> getTokenValidator()
|
||||
{
|
||||
return UTF8Type.instance;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@ import java.util.*;
|
|||
|
||||
import org.apache.cassandra.exceptions.ConfigurationException;
|
||||
import org.apache.cassandra.db.DecoratedKey;
|
||||
import org.apache.cassandra.db.marshal.AbstractType;
|
||||
import org.apache.cassandra.db.marshal.IntegerType;
|
||||
import org.apache.cassandra.utils.ByteBufferUtil;
|
||||
import org.apache.cassandra.utils.FBUtilities;
|
||||
import org.apache.cassandra.utils.GuidGenerator;
|
||||
|
|
@ -183,4 +185,9 @@ public class RandomPartitioner extends AbstractPartitioner<BigIntegerToken>
|
|||
}
|
||||
return ownerships;
|
||||
}
|
||||
|
||||
public AbstractType<?> getTokenValidator()
|
||||
{
|
||||
return IntegerType.instance;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1176,16 +1176,16 @@ public class StorageService extends NotificationBroadcasterSupport implements IE
|
|||
handleStateRelocating(endpoint, pieces);
|
||||
break;
|
||||
case RELEASE_VERSION:
|
||||
SystemTable.updatePeerInfo(endpoint, "release_version", value.value);
|
||||
SystemTable.updatePeerInfo(endpoint, "release_version", quote(value.value));
|
||||
break;
|
||||
case DC:
|
||||
SystemTable.updatePeerInfo(endpoint, "data_center", value.value);
|
||||
SystemTable.updatePeerInfo(endpoint, "data_center", quote(value.value));
|
||||
break;
|
||||
case RACK:
|
||||
SystemTable.updatePeerInfo(endpoint, "rack", value.value);
|
||||
SystemTable.updatePeerInfo(endpoint, "rack", quote(value.value));
|
||||
break;
|
||||
case RPC_ADDRESS:
|
||||
SystemTable.updatePeerInfo(endpoint, "rpc_address", value.value);
|
||||
SystemTable.updatePeerInfo(endpoint, "rpc_address", quote(value.value));
|
||||
break;
|
||||
case SCHEMA:
|
||||
SystemTable.updatePeerInfo(endpoint, "schema_version", value.value);
|
||||
|
|
@ -1196,6 +1196,11 @@ public class StorageService extends NotificationBroadcasterSupport implements IE
|
|||
}
|
||||
}
|
||||
|
||||
private String quote(String value)
|
||||
{
|
||||
return "'" + value + "'";
|
||||
}
|
||||
|
||||
private byte[] getApplicationStateValue(InetAddress endpoint, ApplicationState appstate)
|
||||
{
|
||||
String vvalue = Gossiper.instance.getEndpointStateForEndpoint(endpoint).getApplicationState(appstate).value;
|
||||
|
|
|
|||
Loading…
Reference in New Issue