You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cassandra.apache.org by sl...@apache.org on 2016/06/15 07:39:05 UTC
[4/4] cassandra git commit: Allow terms in selection clauses
Allow terms in selection clauses
patch by slebresne; reviewed by blerer for CASSANDRA-10783
Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo
Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/4ed00607
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/4ed00607
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/4ed00607
Branch: refs/heads/trunk
Commit: 4ed00607df060a3cdcc685c4fc0c1967f62b37f1
Parents: 60e5e0e
Author: Sylvain Lebresne <sy...@datastax.com>
Authored: Tue May 24 15:49:48 2016 +0200
Committer: Sylvain Lebresne <sy...@datastax.com>
Committed: Wed Jun 15 09:33:06 2016 +0200
----------------------------------------------------------------------
CHANGES.txt | 1 +
NEWS.txt | 10 +
doc/cql3/CQL.textile | 8 +-
pylib/cqlshlib/cql3handling.py | 1 +
src/antlr/Cql.g | 1 +
src/antlr/Parser.g | 103 +++---
.../cassandra/config/ColumnDefinition.java | 202 ++++++++++-
.../apache/cassandra/config/ViewDefinition.java | 4 +-
.../apache/cassandra/cql3/AbstractMarker.java | 7 +
.../apache/cassandra/cql3/ColumnCondition.java | 40 +--
.../apache/cassandra/cql3/ColumnIdentifier.java | 143 +-------
.../org/apache/cassandra/cql3/Constants.java | 24 +-
.../apache/cassandra/cql3/FieldIdentifier.java | 98 ++++++
src/java/org/apache/cassandra/cql3/Json.java | 11 +
src/java/org/apache/cassandra/cql3/Lists.java | 13 +
src/java/org/apache/cassandra/cql3/Maps.java | 19 +-
.../cassandra/cql3/MultiColumnRelation.java | 20 +-
.../org/apache/cassandra/cql3/Operation.java | 41 ++-
.../org/apache/cassandra/cql3/Relation.java | 27 +-
src/java/org/apache/cassandra/cql3/Sets.java | 12 +
.../cassandra/cql3/SingleColumnRelation.java | 26 +-
src/java/org/apache/cassandra/cql3/Term.java | 14 +-
.../apache/cassandra/cql3/TokenRelation.java | 16 +-
src/java/org/apache/cassandra/cql3/Tuples.java | 24 ++
.../org/apache/cassandra/cql3/TypeCast.java | 5 +
.../org/apache/cassandra/cql3/UserTypes.java | 44 +--
.../cassandra/cql3/functions/FunctionCall.java | 10 +
.../selection/AbstractFunctionSelector.java | 23 +-
.../selection/AggregateFunctionSelector.java | 4 +-
.../cassandra/cql3/selection/FieldSelector.java | 11 +-
.../cql3/selection/ScalarFunctionSelector.java | 6 +-
.../cassandra/cql3/selection/Selectable.java | 350 ++++++++++++++-----
.../cassandra/cql3/selection/Selection.java | 36 +-
.../cassandra/cql3/selection/Selector.java | 32 +-
.../cql3/selection/SelectorFactories.java | 31 +-
.../cql3/selection/SimpleSelector.java | 3 +-
.../cassandra/cql3/selection/TermSelector.java | 92 +++++
.../cql3/selection/WritetimeOrTTLSelector.java | 3 +-
.../cql3/statements/AlterTableStatement.java | 23 +-
.../statements/AlterTableStatementColumn.java | 24 +-
.../cql3/statements/AlterTypeStatement.java | 44 +--
.../cql3/statements/CreateTypeStatement.java | 18 +-
.../cql3/statements/CreateViewStatement.java | 53 ++-
.../cql3/statements/DeleteStatement.java | 2 +-
.../cassandra/cql3/statements/IndexTarget.java | 22 +-
.../cql3/statements/ModificationStatement.java | 24 +-
.../cql3/statements/SelectStatement.java | 84 ++---
.../cql3/statements/UpdateStatement.java | 16 +-
.../cassandra/db/marshal/AbstractType.java | 24 +-
.../apache/cassandra/db/marshal/TypeParser.java | 7 +-
.../apache/cassandra/db/marshal/UserType.java | 41 +--
src/java/org/apache/cassandra/db/view/View.java | 4 +-
.../exceptions/UnrecognizedEntityException.java | 49 ---
.../cassandra/schema/LegacySchemaMigrator.java | 5 +-
.../apache/cassandra/schema/SchemaKeyspace.java | 2 +-
src/java/org/apache/cassandra/schema/Types.java | 5 +-
.../apache/cassandra/transport/DataType.java | 11 +-
.../cassandra/cql3/CQL3TypeLiteralTest.java | 4 +-
.../org/apache/cassandra/cql3/CQLTester.java | 5 +
.../cql3/selection/TermSelectionTest.java | 338 ++++++++++++++++++
.../validation/operations/AggregationTest.java | 6 +-
.../cql3/validation/operations/DeleteTest.java | 16 +-
.../cql3/validation/operations/InsertTest.java | 16 +-
.../SelectMultiColumnRelationTest.java | 12 +-
.../SelectOrderedPartitionerTest.java | 8 +-
.../SelectSingleColumnRelationTest.java | 22 +-
.../cql3/validation/operations/SelectTest.java | 8 +-
.../cql3/validation/operations/UpdateTest.java | 12 +-
.../schema/LegacySchemaMigratorTest.java | 22 +-
.../cassandra/transport/SerDeserTest.java | 18 +-
70 files changed, 1631 insertions(+), 829 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cassandra/blob/4ed00607/CHANGES.txt
----------------------------------------------------------------------
diff --git a/CHANGES.txt b/CHANGES.txt
index 8689b7d..dbcfa34 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,4 +1,5 @@
3.8
+ * Allow terms in selection clause (CASSANDRA-10783)
* Add bind variables to trace (CASSANDRA-11719)
* Switch counter shards' clock to timestamps (CASSANDRA-9811)
* Introduce HdrHistogram and response/service/wait separation to stress tool (CASSANDRA-11853)
http://git-wip-us.apache.org/repos/asf/cassandra/blob/4ed00607/NEWS.txt
----------------------------------------------------------------------
diff --git a/NEWS.txt b/NEWS.txt
index 076d024..f9430ac 100644
--- a/NEWS.txt
+++ b/NEWS.txt
@@ -38,6 +38,16 @@ Deprecation
cause increased compaction load for a while after the migration so make sure you run
tests before migrating. Read CASSANDRA-9666 for background on this.
+Upgrading
+---------
+ - The name "json" and "distinct" are not valid anymore a user-defined function
+ names (they are still valid as column name however). In the unlikely case where
+ you had defined functions with such names, you will need to recreate
+ those under a different name, change your code to use the new names and
+ drop the old versions, and this _before_ upgrade (see CASSANDRA-10783 for more
+ details).
+
+
3.7
===
http://git-wip-us.apache.org/repos/asf/cassandra/blob/4ed00607/doc/cql3/CQL.textile
----------------------------------------------------------------------
diff --git a/doc/cql3/CQL.textile b/doc/cql3/CQL.textile
index 275717c..b4a3403 100644
--- a/doc/cql3/CQL.textile
+++ b/doc/cql3/CQL.textile
@@ -853,10 +853,7 @@ bc(syntax)..
<names-list> ::= '(' <identifier> ( ',' <identifier> )* ')'
-<value-list> ::= '(' <term-or-literal> ( ',' <term-or-literal> )* ')'
-
-<term-or-literal> ::= <term>
- | <collection-literal>
+<value-list> ::= '(' <term> ( ',' <term> )* ')'
<option> ::= TIMESTAMP <integer>
| TTL <integer>
@@ -1070,13 +1067,14 @@ bc(syntax)..
( ALLOW FILTERING )?
<select-clause> ::= DISTINCT? <selection-list>
- | COUNT '(' ( '*' | '1' ) ')' (AS <identifier>)?
<selection-list> ::= <selector> (AS <identifier>)? ( ',' <selector> (AS <identifier>)? )*
| '*'
<selector> ::= <identifier>
+ | <term>
| WRITETIME '(' <identifier> ')'
+ | COUNT '(' '*' ')'
| TTL '(' <identifier> ')'
| CAST '(' <selector> AS <type> ')'
| <function> '(' (<selector> (',' <selector>)*)? ')'
http://git-wip-us.apache.org/repos/asf/cassandra/blob/4ed00607/pylib/cqlshlib/cql3handling.py
----------------------------------------------------------------------
diff --git a/pylib/cqlshlib/cql3handling.py b/pylib/cqlshlib/cql3handling.py
index 2f88e27..31a8459 100644
--- a/pylib/cqlshlib/cql3handling.py
+++ b/pylib/cqlshlib/cql3handling.py
@@ -702,6 +702,7 @@ syntax_rules += r'''
| "COUNT" "(" star=( "*" | "1" ) ")"
| "CAST" "(" <selector> "AS" <storageType> ")"
| <functionName> <selectionFunctionArguments>
+ | <term>
;
<selectionFunctionArguments> ::= "(" ( <selector> ( "," <selector> )* )? ")"
;
http://git-wip-us.apache.org/repos/asf/cassandra/blob/4ed00607/src/antlr/Cql.g
----------------------------------------------------------------------
diff --git a/src/antlr/Cql.g b/src/antlr/Cql.g
index 7cc16a3..61bdc43 100644
--- a/src/antlr/Cql.g
+++ b/src/antlr/Cql.g
@@ -40,6 +40,7 @@ import Parser,Lexer;
import java.util.Set;
import org.apache.cassandra.auth.*;
+ import org.apache.cassandra.config.ColumnDefinition;
import org.apache.cassandra.cql3.*;
import org.apache.cassandra.cql3.restrictions.CustomIndexExpression;
import org.apache.cassandra.cql3.statements.*;
http://git-wip-us.apache.org/repos/asf/cassandra/blob/4ed00607/src/antlr/Parser.g
----------------------------------------------------------------------
diff --git a/src/antlr/Parser.g b/src/antlr/Parser.g
index deaf5d0..cdb2263 100644
--- a/src/antlr/Parser.g
+++ b/src/antlr/Parser.g
@@ -133,9 +133,9 @@ options {
return res;
}
- public void addRawUpdate(List<Pair<ColumnIdentifier.Raw, Operation.RawUpdate>> operations, ColumnIdentifier.Raw key, Operation.RawUpdate update)
+ public void addRawUpdate(List<Pair<ColumnDefinition.Raw, Operation.RawUpdate>> operations, ColumnDefinition.Raw key, Operation.RawUpdate update)
{
- for (Pair<ColumnIdentifier.Raw, Operation.RawUpdate> p : operations)
+ for (Pair<ColumnDefinition.Raw, Operation.RawUpdate> p : operations)
{
if (p.left.equals(key) && !p.right.isCompatibleWith(update))
addRecognitionError("Multiple incompatible setting of column " + key);
@@ -247,7 +247,7 @@ selectStatement returns [SelectStatement.RawStatement expr]
boolean isDistinct = false;
Term.Raw limit = null;
Term.Raw perPartitionLimit = null;
- Map<ColumnIdentifier.Raw, Boolean> orderings = new LinkedHashMap<ColumnIdentifier.Raw, Boolean>();
+ Map<ColumnDefinition.Raw, Boolean> orderings = new LinkedHashMap<>();
boolean allowFiltering = false;
boolean isJson = false;
}
@@ -280,15 +280,21 @@ selector returns [RawSelector s]
: us=unaliasedSelector (K_AS c=noncol_ident { alias = c; })? { $s = new RawSelector(us, alias); }
;
+/*
+ * A single selection. The core of it is selecting a column, but we also allow any term and function, as well as
+ * sub-element selection for UDT.
+ */
unaliasedSelector returns [Selectable.Raw s]
@init { Selectable.Raw tmp = null; }
: ( c=cident { tmp = c; }
- | K_COUNT '(' countArgument ')' { tmp = Selectable.WithFunction.Raw.newCountRowsFunction();}
+ | v=value { tmp = new Selectable.WithTerm.Raw(v); }
+ | '(' ct=comparatorType ')' v=value { tmp = new Selectable.WithTerm.Raw(new TypeCast(ct, v)); }
+ | K_COUNT '(' '\*' ')' { tmp = Selectable.WithFunction.Raw.newCountRowsFunction(); }
| K_WRITETIME '(' c=cident ')' { tmp = new Selectable.WritetimeOrTTL.Raw(c, true); }
| K_TTL '(' c=cident ')' { tmp = new Selectable.WritetimeOrTTL.Raw(c, false); }
| K_CAST '(' sn=unaliasedSelector K_AS t=native_type ')' {tmp = new Selectable.WithCast.Raw(sn, t);}
| f=functionName args=selectionFunctionArgs { tmp = new Selectable.WithFunction.Raw(f, args); }
- ) ( '.' fi=cident { tmp = new Selectable.WithFieldSelection.Raw(tmp, fi); } )* { $s = tmp; }
+ ) ( '.' fi=fident { tmp = new Selectable.WithFieldSelection.Raw(tmp, fi); } )* { $s = tmp; }
;
selectionFunctionArgs returns [List<Selectable.Raw> a]
@@ -298,11 +304,6 @@ selectionFunctionArgs returns [List<Selectable.Raw> a]
')' { $a = args; }
;
-countArgument
- : '\*'
- | i=INTEGER { if (!i.getText().equals("1")) addRecognitionError("Only COUNT(1) is supported, got COUNT(" + i.getText() + ")");}
- ;
-
whereClause returns [WhereClause.Builder clause]
@init{ $clause = new WhereClause.Builder(); }
: relationOrExpression[$clause] (K_AND relationOrExpression[$clause])*
@@ -318,7 +319,7 @@ customIndexExpression [WhereClause.Builder clause]
: 'expr(' idxName[name] ',' t=term ')' { clause.add(new CustomIndexExpression(name, t));}
;
-orderByClause[Map<ColumnIdentifier.Raw, Boolean> orderings]
+orderByClause[Map<ColumnDefinition.Raw, Boolean> orderings]
@init{
boolean reversed = false;
}
@@ -340,8 +341,8 @@ insertStatement returns [ModificationStatement.Parsed expr]
normalInsertStatement [CFName cf] returns [UpdateStatement.ParsedInsert expr]
@init {
Attributes.Raw attrs = new Attributes.Raw();
- List<ColumnIdentifier.Raw> columnNames = new ArrayList<ColumnIdentifier.Raw>();
- List<Term.Raw> values = new ArrayList<Term.Raw>();
+ List<ColumnDefinition.Raw> columnNames = new ArrayList<>();
+ List<Term.Raw> values = new ArrayList<>();
boolean ifNotExists = false;
}
: '(' c1=cident { columnNames.add(c1); } ( ',' cn=cident { columnNames.add(cn); } )* ')'
@@ -393,7 +394,7 @@ usingClauseObjective[Attributes.Raw attrs]
updateStatement returns [UpdateStatement.ParsedUpdate expr]
@init {
Attributes.Raw attrs = new Attributes.Raw();
- List<Pair<ColumnIdentifier.Raw, Operation.RawUpdate>> operations = new ArrayList<Pair<ColumnIdentifier.Raw, Operation.RawUpdate>>();
+ List<Pair<ColumnDefinition.Raw, Operation.RawUpdate>> operations = new ArrayList<>();
boolean ifExists = false;
}
: K_UPDATE cf=columnFamilyName
@@ -406,13 +407,13 @@ updateStatement returns [UpdateStatement.ParsedUpdate expr]
attrs,
operations,
wclause.build(),
- conditions == null ? Collections.<Pair<ColumnIdentifier.Raw, ColumnCondition.Raw>>emptyList() : conditions,
+ conditions == null ? Collections.<Pair<ColumnDefinition.Raw, ColumnCondition.Raw>>emptyList() : conditions,
ifExists);
}
;
-updateConditions returns [List<Pair<ColumnIdentifier.Raw, ColumnCondition.Raw>> conditions]
- @init { conditions = new ArrayList<Pair<ColumnIdentifier.Raw, ColumnCondition.Raw>>(); }
+updateConditions returns [List<Pair<ColumnDefinition.Raw, ColumnCondition.Raw>> conditions]
+ @init { conditions = new ArrayList<Pair<ColumnDefinition.Raw, ColumnCondition.Raw>>(); }
: columnCondition[conditions] ( K_AND columnCondition[conditions] )*
;
@@ -440,7 +441,7 @@ deleteStatement returns [DeleteStatement.Parsed expr]
attrs,
columnDeletions,
wclause.build(),
- conditions == null ? Collections.<Pair<ColumnIdentifier.Raw, ColumnCondition.Raw>>emptyList() : conditions,
+ conditions == null ? Collections.<Pair<ColumnDefinition.Raw, ColumnCondition.Raw>>emptyList() : conditions,
ifExists);
}
;
@@ -454,7 +455,7 @@ deleteSelection returns [List<Operation.RawDeletion> operations]
deleteOp returns [Operation.RawDeletion op]
: c=cident { $op = new Operation.ColumnDeletion(c); }
| c=cident '[' t=term ']' { $op = new Operation.ElementDeletion(c, t); }
- | c=cident '.' field=cident { $op = new Operation.FieldDeletion(c, field); }
+ | c=cident '.' field=fident { $op = new Operation.FieldDeletion(c, field); }
;
usingClauseDelete[Attributes.Raw attrs]
@@ -673,7 +674,7 @@ createTypeStatement returns [CreateTypeStatement expr]
;
typeColumns[CreateTypeStatement expr]
- : k=noncol_ident v=comparatorType { $expr.addDefinition(k, v); }
+ : k=fident v=comparatorType { $expr.addDefinition(k, v); }
;
@@ -714,8 +715,8 @@ indexIdent [List<IndexTarget.Raw> targets]
createMaterializedViewStatement returns [CreateViewStatement expr]
@init {
boolean ifNotExists = false;
- List<ColumnIdentifier.Raw> partitionKeys = new ArrayList<>();
- List<ColumnIdentifier.Raw> compositeKeys = new ArrayList<>();
+ List<ColumnDefinition.Raw> partitionKeys = new ArrayList<>();
+ List<ColumnDefinition.Raw> compositeKeys = new ArrayList<>();
}
: K_CREATE K_MATERIALIZED K_VIEW (K_IF K_NOT K_EXISTS { ifNotExists = true; })? cf=columnFamilyName K_AS
K_SELECT sclause=selectClause K_FROM basecf=columnFamilyName
@@ -740,7 +741,7 @@ createTriggerStatement returns [CreateTriggerStatement expr]
}
: K_CREATE K_TRIGGER (K_IF K_NOT K_EXISTS { ifNotExists = true; } )? (name=cident)
K_ON cf=columnFamilyName K_USING cls=STRING_LITERAL
- { $expr = new CreateTriggerStatement(cf, name.toString(), $cls.text, ifNotExists); }
+ { $expr = new CreateTriggerStatement(cf, name.rawText(), $cls.text, ifNotExists); }
;
/**
@@ -749,7 +750,7 @@ createTriggerStatement returns [CreateTriggerStatement expr]
dropTriggerStatement returns [DropTriggerStatement expr]
@init { boolean ifExists = false; }
: K_DROP K_TRIGGER (K_IF K_EXISTS { ifExists = true; } )? (name=cident) K_ON cf=columnFamilyName
- { $expr = new DropTriggerStatement(cf, name.toString(), ifExists); }
+ { $expr = new DropTriggerStatement(cf, name.rawText(), ifExists); }
;
/**
@@ -773,7 +774,7 @@ alterTableStatement returns [AlterTableStatement expr]
@init {
AlterTableStatement.Type type = null;
TableAttributes attrs = new TableAttributes();
- Map<ColumnIdentifier.Raw, ColumnIdentifier.Raw> renames = new HashMap<ColumnIdentifier.Raw, ColumnIdentifier.Raw>();
+ Map<ColumnDefinition.Raw, ColumnDefinition.Raw> renames = new HashMap<ColumnDefinition.Raw, ColumnDefinition.Raw>();
List<AlterTableStatementColumn> colNameList = new ArrayList<AlterTableStatementColumn>();
}
: K_ALTER K_COLUMNFAMILY cf=columnFamilyName
@@ -821,12 +822,12 @@ alterMaterializedViewStatement returns [AlterViewStatement expr]
*/
alterTypeStatement returns [AlterTypeStatement expr]
: K_ALTER K_TYPE name=userTypeName
- ( K_ALTER f=noncol_ident K_TYPE v=comparatorType { $expr = AlterTypeStatement.alter(name, f, v); }
- | K_ADD f=noncol_ident v=comparatorType { $expr = AlterTypeStatement.addition(name, f, v); }
+ ( K_ALTER f=fident K_TYPE v=comparatorType { $expr = AlterTypeStatement.alter(name, f, v); }
+ | K_ADD f=fident v=comparatorType { $expr = AlterTypeStatement.addition(name, f, v); }
| K_RENAME
- { Map<ColumnIdentifier, ColumnIdentifier> renames = new HashMap<ColumnIdentifier, ColumnIdentifier>(); }
- id1=noncol_ident K_TO toId1=noncol_ident { renames.put(id1, toId1); }
- ( K_AND idn=noncol_ident K_TO toIdn=noncol_ident { renames.put(idn, toIdn); } )*
+ { Map<FieldIdentifier, FieldIdentifier> renames = new HashMap<>(); }
+ id1=fident K_TO toId1=fident { renames.put(id1, toId1); }
+ ( K_AND idn=fident K_TO toIdn=fident { renames.put(idn, toIdn); } )*
{ $expr = AlterTypeStatement.renames(name, renames); }
)
;
@@ -1144,10 +1145,10 @@ userPassword[RoleOptions opts]
// Column Identifiers. These need to be treated differently from other
// identifiers because the underlying comparator is not necessarily text. See
// CASSANDRA-8178 for details.
-cident returns [ColumnIdentifier.Raw id]
- : t=IDENT { $id = new ColumnIdentifier.Literal($t.text, false); }
- | t=QUOTED_NAME { $id = new ColumnIdentifier.Literal($t.text, true); }
- | k=unreserved_keyword { $id = new ColumnIdentifier.Literal(k, false); }
+cident returns [ColumnDefinition.Raw id]
+ : t=IDENT { $id = ColumnDefinition.Raw.forUnquoted($t.text); }
+ | t=QUOTED_NAME { $id = ColumnDefinition.Raw.forQuoted($t.text); }
+ | k=unreserved_keyword { $id = ColumnDefinition.Raw.forUnquoted(k); }
;
// Column identifiers where the comparator is known to be text
@@ -1157,6 +1158,12 @@ ident returns [ColumnIdentifier id]
| k=unreserved_keyword { $id = ColumnIdentifier.getInterned(k, false); }
;
+fident returns [FieldIdentifier id]
+ : t=IDENT { $id = FieldIdentifier.forUnquoted($t.text); }
+ | t=QUOTED_NAME { $id = FieldIdentifier.forQuoted($t.text); }
+ | k=unreserved_keyword { $id = FieldIdentifier.forUnquoted(k); }
+ ;
+
// Identifiers that do not refer to columns
noncol_ident returns [ColumnIdentifier id]
: t=IDENT { $id = new ColumnIdentifier($t.text, false); }
@@ -1254,10 +1261,10 @@ collectionLiteral returns [Term.Raw value]
;
usertypeLiteral returns [UserTypes.Literal ut]
- @init{ Map<ColumnIdentifier, Term.Raw> m = new HashMap<ColumnIdentifier, Term.Raw>(); }
+ @init{ Map<FieldIdentifier, Term.Raw> m = new HashMap<>(); }
@after{ $ut = new UserTypes.Literal(m); }
// We don't allow empty literals because that conflicts with sets/maps and is currently useless since we don't allow empty user types
- : '{' k1=noncol_ident ':' v1=term { m.put(k1, v1); } ( ',' kn=noncol_ident ':' vn=term { m.put(kn, vn); } )* '}'
+ : '{' k1=fident ':' v1=term { m.put(k1, v1); } ( ',' kn=fident ':' vn=term { m.put(kn, vn); } )* '}'
;
tupleLiteral returns [Tuples.Literal tt]
@@ -1311,17 +1318,17 @@ term returns [Term.Raw term]
| '(' c=comparatorType ')' t=term { $term = new TypeCast(c, t); }
;
-columnOperation[List<Pair<ColumnIdentifier.Raw, Operation.RawUpdate>> operations]
+columnOperation[List<Pair<ColumnDefinition.Raw, Operation.RawUpdate>> operations]
: key=cident columnOperationDifferentiator[operations, key]
;
-columnOperationDifferentiator[List<Pair<ColumnIdentifier.Raw, Operation.RawUpdate>> operations, ColumnIdentifier.Raw key]
+columnOperationDifferentiator[List<Pair<ColumnDefinition.Raw, Operation.RawUpdate>> operations, ColumnDefinition.Raw key]
: '=' normalColumnOperation[operations, key]
| '[' k=term ']' collectionColumnOperation[operations, key, k]
- | '.' field=cident udtColumnOperation[operations, key, field]
+ | '.' field=fident udtColumnOperation[operations, key, field]
;
-normalColumnOperation[List<Pair<ColumnIdentifier.Raw, Operation.RawUpdate>> operations, ColumnIdentifier.Raw key]
+normalColumnOperation[List<Pair<ColumnDefinition.Raw, Operation.RawUpdate>> operations, ColumnDefinition.Raw key]
: t=term ('+' c=cident )?
{
if (c == null)
@@ -1351,21 +1358,21 @@ normalColumnOperation[List<Pair<ColumnIdentifier.Raw, Operation.RawUpdate>> oper
}
;
-collectionColumnOperation[List<Pair<ColumnIdentifier.Raw, Operation.RawUpdate>> operations, ColumnIdentifier.Raw key, Term.Raw k]
+collectionColumnOperation[List<Pair<ColumnDefinition.Raw, Operation.RawUpdate>> operations, ColumnDefinition.Raw key, Term.Raw k]
: '=' t=term
{
addRawUpdate(operations, key, new Operation.SetElement(k, t));
}
;
-udtColumnOperation[List<Pair<ColumnIdentifier.Raw, Operation.RawUpdate>> operations, ColumnIdentifier.Raw key, ColumnIdentifier.Raw field]
+udtColumnOperation[List<Pair<ColumnDefinition.Raw, Operation.RawUpdate>> operations, ColumnDefinition.Raw key, FieldIdentifier field]
: '=' t=term
{
addRawUpdate(operations, key, new Operation.SetField(field, t));
}
;
-columnCondition[List<Pair<ColumnIdentifier.Raw, ColumnCondition.Raw>> conditions]
+columnCondition[List<Pair<ColumnDefinition.Raw, ColumnCondition.Raw>> conditions]
// Note: we'll reject duplicates later
: key=cident
( op=relationType t=term { conditions.add(Pair.create(key, ColumnCondition.Raw.simpleCondition(t, op))); }
@@ -1380,7 +1387,7 @@ columnCondition[List<Pair<ColumnIdentifier.Raw, ColumnCondition.Raw>> conditions
| marker=inMarker { conditions.add(Pair.create(key, ColumnCondition.Raw.collectionInCondition(element, marker))); }
)
)
- | '.' field=cident
+ | '.' field=fident
( op=relationType t=term { conditions.add(Pair.create(key, ColumnCondition.Raw.udtFieldCondition(t, field, op))); }
| K_IN
( values=singleColumnInValues { conditions.add(Pair.create(key, ColumnCondition.Raw.udtFieldInCondition(field, values))); }
@@ -1454,8 +1461,8 @@ inMarker returns [AbstractMarker.INRaw marker]
| ':' name=noncol_ident { $marker = newINBindVariables(name); }
;
-tupleOfIdentifiers returns [List<ColumnIdentifier.Raw> ids]
- @init { $ids = new ArrayList<ColumnIdentifier.Raw>(); }
+tupleOfIdentifiers returns [List<ColumnDefinition.Raw> ids]
+ @init { $ids = new ArrayList<ColumnDefinition.Raw>(); }
: '(' n1=cident { $ids.add(n1); } (',' ni=cident { $ids.add(ni); })* ')'
;
@@ -1572,7 +1579,7 @@ non_type_ident returns [ColumnIdentifier id]
unreserved_keyword returns [String str]
: u=unreserved_function_keyword { $str = u; }
- | k=(K_TTL | K_COUNT | K_WRITETIME | K_KEY | K_CAST) { $str = $k.text; }
+ | k=(K_TTL | K_COUNT | K_WRITETIME | K_KEY | K_CAST | K_JSON | K_DISTINCT) { $str = $k.text; }
;
unreserved_function_keyword returns [String str]
@@ -1608,7 +1615,6 @@ basic_unreserved_keyword returns [String str]
| K_EXISTS
| K_CUSTOM
| K_TRIGGER
- | K_DISTINCT
| K_CONTAINS
| K_STATIC
| K_FROZEN
@@ -1622,7 +1628,6 @@ basic_unreserved_keyword returns [String str]
| K_INITCOND
| K_RETURNS
| K_LANGUAGE
- | K_JSON
| K_CALLED
| K_INPUT
| K_LIKE
http://git-wip-us.apache.org/repos/asf/cassandra/blob/4ed00607/src/java/org/apache/cassandra/config/ColumnDefinition.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/config/ColumnDefinition.java b/src/java/org/apache/cassandra/config/ColumnDefinition.java
index a900ce7..713d684 100644
--- a/src/java/org/apache/cassandra/config/ColumnDefinition.java
+++ b/src/java/org/apache/cassandra/config/ColumnDefinition.java
@@ -27,11 +27,16 @@ import com.google.common.base.Objects;
import com.google.common.collect.Collections2;
import org.apache.cassandra.cql3.*;
+import org.apache.cassandra.cql3.selection.Selectable;
+import org.apache.cassandra.cql3.selection.Selector;
+import org.apache.cassandra.cql3.selection.SimpleSelector;
import org.apache.cassandra.db.rows.*;
import org.apache.cassandra.db.marshal.*;
+import org.apache.cassandra.exceptions.InvalidRequestException;
import org.apache.cassandra.serializers.MarshalException;
+import org.apache.cassandra.utils.ByteBufferUtil;
-public class ColumnDefinition extends ColumnSpecification implements Comparable<ColumnDefinition>
+public class ColumnDefinition extends ColumnSpecification implements Selectable, Comparable<ColumnDefinition>
{
public static final Comparator<Object> asymmetricColumnDataComparator =
(a, b) -> ((ColumnData) a).column().compareTo((ColumnDefinition) b);
@@ -280,9 +285,15 @@ public class ColumnDefinition extends ColumnSpecification implements Comparable<
}
return result;
}
+
@Override
public String toString()
{
+ return name.toString();
+ }
+
+ public String debugString()
+ {
return MoreObjects.toStringHelper(this)
.add("name", name)
.add("type", type)
@@ -419,4 +430,193 @@ public class ColumnDefinition extends ColumnSpecification implements Comparable<
? ((CollectionType)type).valueComparator()
: type;
}
+
+ public Selector.Factory newSelectorFactory(CFMetaData cfm, AbstractType<?> expectedType, List<ColumnDefinition> defs, VariableSpecifications boundNames) throws InvalidRequestException
+ {
+ return SimpleSelector.newFactory(this, addAndGetIndex(this, defs));
+ }
+
+ public AbstractType<?> getExactTypeIfKnown(String keyspace)
+ {
+ return type;
+ }
+
+ /**
+ * Because Thrift-created tables may have a non-text comparator, we cannot determine the proper 'key' until
+ * we know the comparator. ColumnDefinition.Raw is a placeholder that can be converted to a real ColumnIdentifier
+ * once the comparator is known with prepare(). This should only be used with identifiers that are actual
+ * column names. See CASSANDRA-8178 for more background.
+ */
+ public static abstract class Raw extends Selectable.Raw
+ {
+ /**
+ * Creates a {@code ColumnDefinition.Raw} from an unquoted identifier string.
+ */
+ public static Raw forUnquoted(String text)
+ {
+ return new Literal(text, false);
+ }
+
+ /**
+ * Creates a {@code ColumnDefinition.Raw} from a quoted identifier string.
+ */
+ public static Raw forQuoted(String text)
+ {
+ return new Literal(text, true);
+ }
+
+ /**
+ * Creates a {@code ColumnDefinition.Raw} from a pre-existing {@code ColumnDefinition}
+ * (useful in the rare cases where we already have the column but need
+ * a {@code ColumnDefinition.Raw} for typing purposes).
+ */
+ public static Raw forColumn(ColumnDefinition column)
+ {
+ return new ForColumn(column);
+ }
+
+ /**
+ * Get the identifier corresponding to this raw column, without assuming this is an
+ * existing column (unlike {@link #prepare}).
+ */
+ public abstract ColumnIdentifier getIdentifier(CFMetaData cfm);
+
+ public abstract String rawText();
+
+ @Override
+ public abstract ColumnDefinition prepare(CFMetaData cfm);
+
+ @Override
+ public boolean processesSelection()
+ {
+ return false;
+ }
+
+ @Override
+ public final int hashCode()
+ {
+ return toString().hashCode();
+ }
+
+ @Override
+ public final boolean equals(Object o)
+ {
+ if(!(o instanceof Raw))
+ return false;
+
+ Raw that = (Raw)o;
+ return this.toString().equals(that.toString());
+ }
+
+ private static class Literal extends Raw
+ {
+ private final String text;
+
+ public Literal(String rawText, boolean keepCase)
+ {
+ this.text = keepCase ? rawText : rawText.toLowerCase(Locale.US);
+ }
+
+ public ColumnIdentifier getIdentifier(CFMetaData cfm)
+ {
+ if (!cfm.isStaticCompactTable())
+ return ColumnIdentifier.getInterned(text, true);
+
+ AbstractType<?> thriftColumnNameType = cfm.thriftColumnNameType();
+ if (thriftColumnNameType instanceof UTF8Type)
+ return ColumnIdentifier.getInterned(text, true);
+
+ // We have a Thrift-created table with a non-text comparator. Check if we have a match column, otherwise assume we should use
+ // thriftColumnNameType
+ ByteBuffer bufferName = ByteBufferUtil.bytes(text);
+ for (ColumnDefinition def : cfm.allColumns())
+ {
+ if (def.name.bytes.equals(bufferName))
+ return def.name;
+ }
+ return ColumnIdentifier.getInterned(thriftColumnNameType.fromString(text), text);
+ }
+
+ public ColumnDefinition prepare(CFMetaData cfm)
+ {
+ if (!cfm.isStaticCompactTable())
+ return find(cfm);
+
+ AbstractType<?> thriftColumnNameType = cfm.thriftColumnNameType();
+ if (thriftColumnNameType instanceof UTF8Type)
+ return find(cfm);
+
+ // We have a Thrift-created table with a non-text comparator. Check if we have a match column, otherwise assume we should use
+ // thriftColumnNameType
+ ByteBuffer bufferName = ByteBufferUtil.bytes(text);
+ for (ColumnDefinition def : cfm.allColumns())
+ {
+ if (def.name.bytes.equals(bufferName))
+ return def;
+ }
+ return find(thriftColumnNameType.fromString(text), cfm);
+ }
+
+ private ColumnDefinition find(CFMetaData cfm)
+ {
+ return find(ByteBufferUtil.bytes(text), cfm);
+ }
+
+ private ColumnDefinition find(ByteBuffer id, CFMetaData cfm)
+ {
+ ColumnDefinition def = cfm.getColumnDefinition(id);
+ if (def == null)
+ throw new InvalidRequestException(String.format("Undefined column name %s", toString()));
+ return def;
+ }
+
+ public String rawText()
+ {
+ return text;
+ }
+
+ @Override
+ public String toString()
+ {
+ return ColumnIdentifier.maybeQuote(text);
+ }
+ }
+
+ // Use internally in the rare case where we need a ColumnDefinition.Raw for type-checking but
+ // actually already have the column itself.
+ private static class ForColumn extends Raw
+ {
+ private final ColumnDefinition column;
+
+ private ForColumn(ColumnDefinition column)
+ {
+ this.column = column;
+ }
+
+ public ColumnIdentifier getIdentifier(CFMetaData cfm)
+ {
+ return column.name;
+ }
+
+ public ColumnDefinition prepare(CFMetaData cfm)
+ {
+ assert cfm.getColumnDefinition(column.name) != null; // Sanity check that we're not doing something crazy
+ return column;
+ }
+
+ public String rawText()
+ {
+ return column.name.toString();
+ }
+
+ @Override
+ public String toString()
+ {
+ return column.name.toCQLString();
+ }
+ }
+ }
+
+
+
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/4ed00607/src/java/org/apache/cassandra/config/ViewDefinition.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/config/ViewDefinition.java b/src/java/org/apache/cassandra/config/ViewDefinition.java
index 9cf8476..33cc175 100644
--- a/src/java/org/apache/cassandra/config/ViewDefinition.java
+++ b/src/java/org/apache/cassandra/config/ViewDefinition.java
@@ -139,8 +139,8 @@ public class ViewDefinition
// convert whereClause to Relations, rename ids in Relations, then convert back to whereClause
List<Relation> relations = whereClauseToRelations(whereClause);
- ColumnIdentifier.Raw fromRaw = new ColumnIdentifier.Literal(from.toString(), true);
- ColumnIdentifier.Raw toRaw = new ColumnIdentifier.Literal(to.toString(), true);
+ ColumnDefinition.Raw fromRaw = ColumnDefinition.Raw.forQuoted(from.toString());
+ ColumnDefinition.Raw toRaw = ColumnDefinition.Raw.forQuoted(to.toString());
List<Relation> newRelations = relations.stream()
.map(r -> r.renameIdentifier(fromRaw, toRaw))
.collect(Collectors.toList());
http://git-wip-us.apache.org/repos/asf/cassandra/blob/4ed00607/src/java/org/apache/cassandra/cql3/AbstractMarker.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/AbstractMarker.java b/src/java/org/apache/cassandra/cql3/AbstractMarker.java
index 21644c8..3689ed1 100644
--- a/src/java/org/apache/cassandra/cql3/AbstractMarker.java
+++ b/src/java/org/apache/cassandra/cql3/AbstractMarker.java
@@ -21,6 +21,7 @@ import java.util.Collections;
import java.util.List;
import org.apache.cassandra.cql3.functions.Function;
+import org.apache.cassandra.db.marshal.AbstractType;
import org.apache.cassandra.db.marshal.CollectionType;
import org.apache.cassandra.db.marshal.ListType;
import org.apache.cassandra.exceptions.InvalidRequestException;
@@ -89,11 +90,17 @@ public abstract class AbstractMarker extends Term.NonTerminal
return new Constants.Marker(bindIndex, receiver);
}
+ @Override
public AssignmentTestable.TestResult testAssignment(String keyspace, ColumnSpecification receiver)
{
return AssignmentTestable.TestResult.WEAKLY_ASSIGNABLE;
}
+ public AbstractType<?> getExactTypeIfKnown(String keyspace)
+ {
+ return null;
+ }
+
@Override
public String getText()
{
http://git-wip-us.apache.org/repos/asf/cassandra/blob/4ed00607/src/java/org/apache/cassandra/cql3/ColumnCondition.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/ColumnCondition.java b/src/java/org/apache/cassandra/cql3/ColumnCondition.java
index 255dd0e..304f8bc 100644
--- a/src/java/org/apache/cassandra/cql3/ColumnCondition.java
+++ b/src/java/org/apache/cassandra/cql3/ColumnCondition.java
@@ -42,14 +42,14 @@ public class ColumnCondition
private final Term collectionElement;
// For UDT, when testing the equality of a specific field, null otherwise.
- private final ColumnIdentifier field;
+ private final FieldIdentifier field;
private final Term value; // a single value or a marker for a list of IN values
private final List<Term> inValues;
public final Operator operator;
- private ColumnCondition(ColumnDefinition column, Term collectionElement, ColumnIdentifier field, Term value, List<Term> inValues, Operator op)
+ private ColumnCondition(ColumnDefinition column, Term collectionElement, FieldIdentifier field, Term value, List<Term> inValues, Operator op)
{
this.column = column;
this.collectionElement = collectionElement;
@@ -73,7 +73,7 @@ public class ColumnCondition
return new ColumnCondition(column, collectionElement, null, value, null, op);
}
- public static ColumnCondition condition(ColumnDefinition column, ColumnIdentifier udtField, Term value, Operator op)
+ public static ColumnCondition condition(ColumnDefinition column, FieldIdentifier udtField, Term value, Operator op)
{
return new ColumnCondition(column, null, udtField, value, null, op);
}
@@ -88,7 +88,7 @@ public class ColumnCondition
return new ColumnCondition(column, collectionElement, null, null, inValues, Operator.IN);
}
- public static ColumnCondition inCondition(ColumnDefinition column, ColumnIdentifier udtField, List<Term> inValues)
+ public static ColumnCondition inCondition(ColumnDefinition column, FieldIdentifier udtField, List<Term> inValues)
{
return new ColumnCondition(column, null, udtField, null, inValues, Operator.IN);
}
@@ -103,7 +103,7 @@ public class ColumnCondition
return new ColumnCondition(column, collectionElement, null, inMarker, null, Operator.IN);
}
- public static ColumnCondition inCondition(ColumnDefinition column, ColumnIdentifier udtField, Term inMarker)
+ public static ColumnCondition inCondition(ColumnDefinition column, FieldIdentifier udtField, Term inMarker)
{
return new ColumnCondition(column, null, udtField, inMarker, null, Operator.IN);
}
@@ -693,7 +693,7 @@ public class ColumnCondition
/** A condition on a UDT field. IN operators are not supported here, see UDTFieldAccessInBound. */
static class UDTFieldAccessBound extends Bound
{
- public final ColumnIdentifier field;
+ public final FieldIdentifier field;
public final ByteBuffer value;
private UDTFieldAccessBound(ColumnCondition condition, QueryOptions options) throws InvalidRequestException
@@ -714,7 +714,7 @@ public class ColumnCondition
ByteBuffer cellValue;
if (column.type.isMultiCell())
{
- Cell cell = getCell(row, column, userType.cellPathForField(field.bytes));
+ Cell cell = getCell(row, column, userType.cellPathForField(field));
cellValue = cell == null ? null : cell.value();
}
else
@@ -731,7 +731,7 @@ public class ColumnCondition
/** An IN condition on a UDT field. For example: IF user.name IN ('a', 'b') */
static class UDTFieldAccessInBound extends Bound
{
- public final ColumnIdentifier field;
+ public final FieldIdentifier field;
public final List<ByteBuffer> inValues;
private UDTFieldAccessInBound(ColumnCondition condition, QueryOptions options) throws InvalidRequestException
@@ -759,7 +759,7 @@ public class ColumnCondition
ByteBuffer cellValue;
if (column.type.isMultiCell())
{
- Cell cell = getCell(row, column, userType.cellPathForField(field.bytes));
+ Cell cell = getCell(row, column, userType.cellPathForField(field));
cellValue = cell == null ? null : cell.value();
}
else
@@ -889,12 +889,12 @@ public class ColumnCondition
private final Term.Raw collectionElement;
// Can be null, only used with the syntax "IF udt.field = ..." (in which case it's 'field')
- private final ColumnIdentifier.Raw udtField;
+ private final FieldIdentifier udtField;
private final Operator operator;
private Raw(Term.Raw value, List<Term.Raw> inValues, AbstractMarker.INRaw inMarker, Term.Raw collectionElement,
- ColumnIdentifier.Raw udtField, Operator op)
+ FieldIdentifier udtField, Operator op)
{
this.value = value;
this.inValues = inValues;
@@ -941,19 +941,19 @@ public class ColumnCondition
}
/** A condition on a UDT field. For example: "IF col.field = 'foo'" */
- public static Raw udtFieldCondition(Term.Raw value, ColumnIdentifier.Raw udtField, Operator op)
+ public static Raw udtFieldCondition(Term.Raw value, FieldIdentifier udtField, Operator op)
{
return new Raw(value, null, null, null, udtField, op);
}
/** An IN condition on a collection element. For example: "IF col.field IN ('foo', 'bar', ...)" */
- public static Raw udtFieldInCondition(ColumnIdentifier.Raw udtField, List<Term.Raw> inValues)
+ public static Raw udtFieldInCondition(FieldIdentifier udtField, List<Term.Raw> inValues)
{
return new Raw(null, inValues, null, null, udtField, Operator.IN);
}
/** An IN condition on a collection element with a single marker. For example: "IF col.field IN ?" */
- public static Raw udtFieldInCondition(ColumnIdentifier.Raw udtField, AbstractMarker.INRaw inMarker)
+ public static Raw udtFieldInCondition(FieldIdentifier udtField, AbstractMarker.INRaw inMarker)
{
return new Raw(null, null, inMarker, null, udtField, Operator.IN);
}
@@ -1001,26 +1001,24 @@ public class ColumnCondition
else if (udtField != null)
{
UserType userType = (UserType) receiver.type;
- ColumnIdentifier fieldIdentifier = udtField.prepare(cfm);
-
- int fieldPosition = userType.fieldPosition(fieldIdentifier);
+ int fieldPosition = userType.fieldPosition(udtField);
if (fieldPosition == -1)
- throw new InvalidRequestException(String.format("Unknown field %s for column %s", fieldIdentifier, receiver.name));
+ throw new InvalidRequestException(String.format("Unknown field %s for column %s", udtField, receiver.name));
ColumnSpecification fieldReceiver = UserTypes.fieldSpecOf(receiver, fieldPosition);
if (operator == Operator.IN)
{
if (inValues == null)
- return ColumnCondition.inCondition(receiver, udtField.prepare(cfm), inMarker.prepare(keyspace, fieldReceiver));
+ return ColumnCondition.inCondition(receiver, udtField, inMarker.prepare(keyspace, fieldReceiver));
List<Term> terms = new ArrayList<>(inValues.size());
for (Term.Raw value : inValues)
terms.add(value.prepare(keyspace, fieldReceiver));
- return ColumnCondition.inCondition(receiver, udtField.prepare(cfm), terms);
+ return ColumnCondition.inCondition(receiver, udtField, terms);
}
else
{
- return ColumnCondition.condition(receiver, udtField.prepare(cfm), value.prepare(keyspace, fieldReceiver), operator);
+ return ColumnCondition.condition(receiver, udtField, value.prepare(keyspace, fieldReceiver), operator);
}
}
else
http://git-wip-us.apache.org/repos/asf/cassandra/blob/4ed00607/src/java/org/apache/cassandra/cql3/ColumnIdentifier.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/ColumnIdentifier.java b/src/java/org/apache/cassandra/cql3/ColumnIdentifier.java
index f202145..467c672 100644
--- a/src/java/org/apache/cassandra/cql3/ColumnIdentifier.java
+++ b/src/java/org/apache/cassandra/cql3/ColumnIdentifier.java
@@ -31,8 +31,6 @@ import org.apache.cassandra.cache.IMeasurableMemory;
import org.apache.cassandra.config.CFMetaData;
import org.apache.cassandra.config.ColumnDefinition;
import org.apache.cassandra.cql3.selection.Selectable;
-import org.apache.cassandra.cql3.selection.Selector;
-import org.apache.cassandra.cql3.selection.SimpleSelector;
import org.apache.cassandra.db.marshal.AbstractType;
import org.apache.cassandra.exceptions.InvalidRequestException;
import org.apache.cassandra.db.marshal.UTF8Type;
@@ -44,7 +42,7 @@ import org.apache.cassandra.utils.memory.AbstractAllocator;
* Represents an identifer for a CQL column definition.
* TODO : should support light-weight mode without text representation for when not interned
*/
-public class ColumnIdentifier extends Selectable implements IMeasurableMemory, Comparable<ColumnIdentifier>
+public class ColumnIdentifier implements IMeasurableMemory, Comparable<ColumnIdentifier>
{
private static final Pattern PATTERN_DOUBLE_QUOTE = Pattern.compile("\"", Pattern.LITERAL);
private static final String ESCAPED_DOUBLE_QUOTE = Matcher.quoteReplacement("\"\"");
@@ -157,7 +155,7 @@ public class ColumnIdentifier extends Selectable implements IMeasurableMemory, C
/**
* Returns a string representation of the identifier that is safe to use directly in CQL queries.
- * In necessary, the string will be double-quoted, and any quotes inside the string will be escaped.
+ * If necessary, the string will be double-quoted, and any quotes inside the string will be escaped.
*/
public String toCQLString()
{
@@ -183,15 +181,6 @@ public class ColumnIdentifier extends Selectable implements IMeasurableMemory, C
return interned ? this : new ColumnIdentifier(allocator.clone(bytes), text, false);
}
- public Selector.Factory newSelectorFactory(CFMetaData cfm, List<ColumnDefinition> defs) throws InvalidRequestException
- {
- ColumnDefinition def = cfm.getColumnDefinition(this);
- if (def == null)
- throw new InvalidRequestException(String.format("Undefined name %s in selection clause", this));
-
- return SimpleSelector.newFactory(def, addAndGetIndex(def, defs));
- }
-
public int compareTo(ColumnIdentifier that)
{
int c = Long.compare(this.prefixComparison, that.prefixComparison);
@@ -202,134 +191,6 @@ public class ColumnIdentifier extends Selectable implements IMeasurableMemory, C
return ByteBufferUtil.compareUnsigned(this.bytes, that.bytes);
}
- /**
- * Because Thrift-created tables may have a non-text comparator, we cannot determine the proper 'key' until
- * we know the comparator. ColumnIdentifier.Raw is a placeholder that can be converted to a real ColumnIdentifier
- * once the comparator is known with prepare(). This should only be used with identifiers that are actual
- * column names. See CASSANDRA-8178 for more background.
- */
- public static interface Raw extends Selectable.Raw
- {
-
- public ColumnIdentifier prepare(CFMetaData cfm);
-
- /**
- * Returns a string representation of the identifier that is safe to use directly in CQL queries.
- * In necessary, the string will be double-quoted, and any quotes inside the string will be escaped.
- */
- public String toCQLString();
- }
-
- public static class Literal implements Raw
- {
- private final String rawText;
- private final String text;
-
- public Literal(String rawText, boolean keepCase)
- {
- this.rawText = rawText;
- this.text = keepCase ? rawText : rawText.toLowerCase(Locale.US);
- }
-
- public ColumnIdentifier prepare(CFMetaData cfm)
- {
- if (!cfm.isStaticCompactTable())
- return getInterned(text, true);
-
- AbstractType<?> thriftColumnNameType = cfm.thriftColumnNameType();
- if (thriftColumnNameType instanceof UTF8Type)
- return getInterned(text, true);
-
- // We have a Thrift-created table with a non-text comparator. Check if we have a match column, otherwise assume we should use
- // thriftColumnNameType
- ByteBuffer bufferName = ByteBufferUtil.bytes(text);
- for (ColumnDefinition def : cfm.allColumns())
- {
- if (def.name.bytes.equals(bufferName))
- return def.name;
- }
- return getInterned(thriftColumnNameType.fromString(rawText), text);
- }
-
- public boolean processesSelection()
- {
- return false;
- }
-
- @Override
- public final int hashCode()
- {
- return text.hashCode();
- }
-
- @Override
- public final boolean equals(Object o)
- {
- if(!(o instanceof Literal))
- return false;
-
- Literal that = (Literal) o;
- return text.equals(that.text);
- }
-
- @Override
- public String toString()
- {
- return text;
- }
-
- public String toCQLString()
- {
- return maybeQuote(text);
- }
- }
-
- public static class ColumnIdentifierValue implements Raw
- {
- private final ColumnIdentifier identifier;
-
- public ColumnIdentifierValue(ColumnIdentifier identifier)
- {
- this.identifier = identifier;
- }
-
- public ColumnIdentifier prepare(CFMetaData cfm)
- {
- return identifier;
- }
-
- public boolean processesSelection()
- {
- return false;
- }
-
- @Override
- public final int hashCode()
- {
- return identifier.hashCode();
- }
-
- @Override
- public final boolean equals(Object o)
- {
- if(!(o instanceof ColumnIdentifierValue))
- return false;
- ColumnIdentifierValue that = (ColumnIdentifierValue) o;
- return identifier.equals(that.identifier);
- }
-
- @Override
- public String toString()
- {
- return identifier.toString();
- }
-
- public String toCQLString()
- {
- return maybeQuote(identifier.text);
- }
- }
-
@VisibleForTesting
public static String maybeQuote(String text)
{
http://git-wip-us.apache.org/repos/asf/cassandra/blob/4ed00607/src/java/org/apache/cassandra/cql3/Constants.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/Constants.java b/src/java/org/apache/cassandra/cql3/Constants.java
index 2efce59..6589d85 100644
--- a/src/java/org/apache/cassandra/cql3/Constants.java
+++ b/src/java/org/apache/cassandra/cql3/Constants.java
@@ -23,11 +23,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.cassandra.config.ColumnDefinition;
import org.apache.cassandra.db.*;
-import org.apache.cassandra.db.marshal.AbstractType;
-import org.apache.cassandra.db.marshal.BytesType;
-import org.apache.cassandra.db.marshal.CounterColumnType;
-import org.apache.cassandra.db.marshal.LongType;
-import org.apache.cassandra.db.marshal.ReversedType;
+import org.apache.cassandra.db.marshal.*;
import org.apache.cassandra.exceptions.InvalidRequestException;
import org.apache.cassandra.serializers.MarshalException;
import org.apache.cassandra.utils.ByteBufferUtil;
@@ -41,7 +37,7 @@ public abstract class Constants
public enum Type
{
- STRING, INTEGER, UUID, FLOAT, DATE, TIME, BOOLEAN, HEX;
+ STRING, INTEGER, UUID, FLOAT, BOOLEAN, HEX;
}
public static final Value UNSET_VALUE = new Value(ByteBufferUtil.UNSET_BYTE_BUFFER);
@@ -67,6 +63,11 @@ public abstract class Constants
{
return "NULL";
}
+
+ public AbstractType<?> getExactTypeIfKnown(String keyspace)
+ {
+ return null;
+ }
}
public static final NullLiteral NULL_LITERAL = new NullLiteral();
@@ -159,6 +160,7 @@ public abstract class Constants
}
}
+ @Override
public AssignmentTestable.TestResult testAssignment(String keyspace, ColumnSpecification receiver)
{
CQL3Type receiverType = receiver.type.asCQL3Type();
@@ -237,6 +239,16 @@ public abstract class Constants
return AssignmentTestable.TestResult.NOT_ASSIGNABLE;
}
+ public AbstractType<?> getExactTypeIfKnown(String keyspace)
+ {
+ // Most constant are valid for more than one type (the extreme example being integer constants, which can
+ // be use for any numerical type, including date, time, ...) so they don't have an exact type. And in fact,
+ // for good or bad, any literal is valid for custom types, so we can never claim an exact type.
+ // But really, the reason it's fine to return null here is that getExactTypeIfKnown is only used to
+ // implement testAssignment() in Selectable and that method is overriden above.
+ return null;
+ }
+
public String getRawText()
{
return text;
http://git-wip-us.apache.org/repos/asf/cassandra/blob/4ed00607/src/java/org/apache/cassandra/cql3/FieldIdentifier.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/FieldIdentifier.java b/src/java/org/apache/cassandra/cql3/FieldIdentifier.java
new file mode 100644
index 0000000..5e0601c
--- /dev/null
+++ b/src/java/org/apache/cassandra/cql3/FieldIdentifier.java
@@ -0,0 +1,98 @@
+/*
+ * 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.cql3;
+
+import java.util.Locale;
+import java.nio.ByteBuffer;
+
+import org.apache.cassandra.db.marshal.UTF8Type;
+import org.apache.cassandra.exceptions.SyntaxException;
+import org.apache.cassandra.utils.ByteBufferUtil;
+import org.apache.cassandra.serializers.MarshalException;
+
+/**
+ * Identifies a field in a UDT.
+ */
+public class FieldIdentifier
+{
+ public final ByteBuffer bytes;
+
+ public FieldIdentifier(ByteBuffer bytes)
+ {
+ this.bytes = bytes;
+ }
+
+ /**
+ * Creates a {@code FieldIdentifier} from an unquoted identifier string.
+ */
+ public static FieldIdentifier forUnquoted(String text)
+ {
+ return new FieldIdentifier(convert(text.toLowerCase(Locale.US)));
+ }
+
+ /**
+ * Creates a {@code FieldIdentifier} from a quoted identifier string.
+ */
+ public static FieldIdentifier forQuoted(String text)
+ {
+ return new FieldIdentifier(convert(text));
+ }
+
+ /**
+ * Creates a {@code FieldIdentifier} from an internal string.
+ */
+ public static FieldIdentifier forInternalString(String text)
+ {
+ // If we store a field internally, we consider it as quoted, i.e. we preserve
+ // whatever case the text has.
+ return forQuoted(text);
+ }
+
+ private static ByteBuffer convert(String text)
+ {
+ try
+ {
+ return UTF8Type.instance.decompose(text);
+ }
+ catch (MarshalException e)
+ {
+ throw new SyntaxException(String.format("For field name %s: %s", text, e.getMessage()));
+ }
+ }
+
+ @Override
+ public String toString()
+ {
+ return UTF8Type.instance.compose(bytes);
+ }
+
+ @Override
+ public final int hashCode()
+ {
+ return bytes.hashCode();
+ }
+
+ @Override
+ public final boolean equals(Object o)
+ {
+ if(!(o instanceof FieldIdentifier))
+ return false;
+ FieldIdentifier that = (FieldIdentifier)o;
+ return this.bytes.equals(that.bytes);
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/4ed00607/src/java/org/apache/cassandra/cql3/Json.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/Json.java b/src/java/org/apache/cassandra/cql3/Json.java
index ab02fb6..298cde7 100644
--- a/src/java/org/apache/cassandra/cql3/Json.java
+++ b/src/java/org/apache/cassandra/cql3/Json.java
@@ -24,6 +24,7 @@ import java.util.*;
import org.apache.cassandra.config.CFMetaData;
import org.apache.cassandra.config.ColumnDefinition;
import org.apache.cassandra.cql3.functions.Function;
+import org.apache.cassandra.db.marshal.AbstractType;
import org.apache.cassandra.db.marshal.UTF8Type;
import org.apache.cassandra.exceptions.InvalidRequestException;
import org.apache.cassandra.serializers.MarshalException;
@@ -180,6 +181,11 @@ public class Json
return TestResult.NOT_ASSIGNABLE;
}
+ public AbstractType<?> getExactTypeIfKnown(String keyspace)
+ {
+ return null;
+ }
+
public String getText()
{
return term.toString();
@@ -212,6 +218,11 @@ public class Json
return TestResult.WEAKLY_ASSIGNABLE;
}
+ public AbstractType<?> getExactTypeIfKnown(String keyspace)
+ {
+ return null;
+ }
+
public String getText()
{
return marker.toString();
http://git-wip-us.apache.org/repos/asf/cassandra/blob/4ed00607/src/java/org/apache/cassandra/cql3/Lists.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/Lists.java b/src/java/org/apache/cassandra/cql3/Lists.java
index aab9c8f..ad0af6d 100644
--- a/src/java/org/apache/cassandra/cql3/Lists.java
+++ b/src/java/org/apache/cassandra/cql3/Lists.java
@@ -29,6 +29,7 @@ import org.apache.cassandra.config.ColumnDefinition;
import org.apache.cassandra.cql3.functions.Function;
import org.apache.cassandra.db.*;
import org.apache.cassandra.db.rows.*;
+import org.apache.cassandra.db.marshal.AbstractType;
import org.apache.cassandra.db.marshal.Int32Type;
import org.apache.cassandra.db.marshal.ListType;
import org.apache.cassandra.exceptions.InvalidRequestException;
@@ -113,6 +114,18 @@ public abstract class Lists
return AssignmentTestable.TestResult.testAll(keyspace, valueSpec, elements);
}
+ @Override
+ public AbstractType<?> getExactTypeIfKnown(String keyspace)
+ {
+ for (Term.Raw term : elements)
+ {
+ AbstractType<?> type = term.getExactTypeIfKnown(keyspace);
+ if (type != null)
+ return ListType.getInstance(type, false);
+ }
+ return null;
+ }
+
public String getText()
{
return elements.stream().map(Term.Raw::getText).collect(Collectors.joining(", ", "[", "]"));
http://git-wip-us.apache.org/repos/asf/cassandra/blob/4ed00607/src/java/org/apache/cassandra/cql3/Maps.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/Maps.java b/src/java/org/apache/cassandra/cql3/Maps.java
index 4772369..952bff0 100644
--- a/src/java/org/apache/cassandra/cql3/Maps.java
+++ b/src/java/org/apache/cassandra/cql3/Maps.java
@@ -27,7 +27,7 @@ import org.apache.cassandra.config.ColumnDefinition;
import org.apache.cassandra.cql3.functions.Function;
import org.apache.cassandra.db.DecoratedKey;
import org.apache.cassandra.db.rows.*;
-import org.apache.cassandra.db.marshal.MapType;
+import org.apache.cassandra.db.marshal.*;
import org.apache.cassandra.exceptions.InvalidRequestException;
import org.apache.cassandra.serializers.CollectionSerializer;
import org.apache.cassandra.serializers.MarshalException;
@@ -127,6 +127,23 @@ public abstract class Maps
return res;
}
+ @Override
+ public AbstractType<?> getExactTypeIfKnown(String keyspace)
+ {
+ AbstractType<?> keyType = null;
+ AbstractType<?> valueType = null;
+ for (Pair<Term.Raw, Term.Raw> entry : entries)
+ {
+ if (keyType == null)
+ keyType = entry.left.getExactTypeIfKnown(keyspace);
+ if (valueType == null)
+ valueType = entry.right.getExactTypeIfKnown(keyspace);
+ if (keyType != null && valueType != null)
+ return MapType.getInstance(keyType, valueType, false);
+ }
+ return null;
+ }
+
public String getText()
{
return entries.stream()
http://git-wip-us.apache.org/repos/asf/cassandra/blob/4ed00607/src/java/org/apache/cassandra/cql3/MultiColumnRelation.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/MultiColumnRelation.java b/src/java/org/apache/cassandra/cql3/MultiColumnRelation.java
index 2c1f97b..01f2a12 100644
--- a/src/java/org/apache/cassandra/cql3/MultiColumnRelation.java
+++ b/src/java/org/apache/cassandra/cql3/MultiColumnRelation.java
@@ -46,7 +46,7 @@ import static org.apache.cassandra.cql3.statements.RequestValidations.invalidReq
*/
public class MultiColumnRelation extends Relation
{
- private final List<ColumnIdentifier.Raw> entities;
+ private final List<ColumnDefinition.Raw> entities;
/** A Tuples.Literal or Tuples.Raw marker */
private final Term.MultiColumnRaw valuesOrMarker;
@@ -56,7 +56,7 @@ public class MultiColumnRelation extends Relation
private final Tuples.INRaw inMarker;
- private MultiColumnRelation(List<ColumnIdentifier.Raw> entities, Operator relationType, Term.MultiColumnRaw valuesOrMarker, List<? extends Term.MultiColumnRaw> inValues, Tuples.INRaw inMarker)
+ private MultiColumnRelation(List<ColumnDefinition.Raw> entities, Operator relationType, Term.MultiColumnRaw valuesOrMarker, List<? extends Term.MultiColumnRaw> inValues, Tuples.INRaw inMarker)
{
this.entities = entities;
this.relationType = relationType;
@@ -76,7 +76,7 @@ public class MultiColumnRelation extends Relation
* @param valuesOrMarker a Tuples.Literal instance or a Tuples.Raw marker
* @return a new <code>MultiColumnRelation</code> instance
*/
- public static MultiColumnRelation createNonInRelation(List<ColumnIdentifier.Raw> entities, Operator relationType, Term.MultiColumnRaw valuesOrMarker)
+ public static MultiColumnRelation createNonInRelation(List<ColumnDefinition.Raw> entities, Operator relationType, Term.MultiColumnRaw valuesOrMarker)
{
assert relationType != Operator.IN;
return new MultiColumnRelation(entities, relationType, valuesOrMarker, null, null);
@@ -89,7 +89,7 @@ public class MultiColumnRelation extends Relation
* @param inValues a list of Tuples.Literal instances or a Tuples.Raw markers
* @return a new <code>MultiColumnRelation</code> instance
*/
- public static MultiColumnRelation createInRelation(List<ColumnIdentifier.Raw> entities, List<? extends Term.MultiColumnRaw> inValues)
+ public static MultiColumnRelation createInRelation(List<ColumnDefinition.Raw> entities, List<? extends Term.MultiColumnRaw> inValues)
{
return new MultiColumnRelation(entities, Operator.IN, null, inValues, null);
}
@@ -101,12 +101,12 @@ public class MultiColumnRelation extends Relation
* @param inMarker a single IN marker
* @return a new <code>MultiColumnRelation</code> instance
*/
- public static MultiColumnRelation createSingleMarkerInRelation(List<ColumnIdentifier.Raw> entities, Tuples.INRaw inMarker)
+ public static MultiColumnRelation createSingleMarkerInRelation(List<ColumnDefinition.Raw> entities, Tuples.INRaw inMarker)
{
return new MultiColumnRelation(entities, Operator.IN, null, null, inMarker);
}
- public List<ColumnIdentifier.Raw> getEntities()
+ public List<ColumnDefinition.Raw> getEntities()
{
return entities;
}
@@ -203,9 +203,9 @@ public class MultiColumnRelation extends Relation
{
List<ColumnDefinition> names = new ArrayList<>(getEntities().size());
int previousPosition = -1;
- for (ColumnIdentifier.Raw raw : getEntities())
+ for (ColumnDefinition.Raw raw : getEntities())
{
- ColumnDefinition def = toColumnDefinition(cfm, raw);
+ ColumnDefinition def = raw.prepare(cfm);
checkTrue(def.isClusteringColumn(), "Multi-column relations can only be applied to clustering columns but was applied to: %s", def.name);
checkFalse(names.contains(def), "Column \"%s\" appeared twice in a relation: %s", def.name, this);
@@ -219,12 +219,12 @@ public class MultiColumnRelation extends Relation
return names;
}
- public Relation renameIdentifier(ColumnIdentifier.Raw from, ColumnIdentifier.Raw to)
+ public Relation renameIdentifier(ColumnDefinition.Raw from, ColumnDefinition.Raw to)
{
if (!entities.contains(from))
return this;
- List<ColumnIdentifier.Raw> newEntities = entities.stream().map(e -> e.equals(from) ? to : e).collect(Collectors.toList());
+ List<ColumnDefinition.Raw> newEntities = entities.stream().map(e -> e.equals(from) ? to : e).collect(Collectors.toList());
return new MultiColumnRelation(newEntities, operator(), valuesOrMarker, inValues, inMarker);
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/4ed00607/src/java/org/apache/cassandra/cql3/Operation.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/Operation.java b/src/java/org/apache/cassandra/cql3/Operation.java
index 0147859..7d7d7b3 100644
--- a/src/java/org/apache/cassandra/cql3/Operation.java
+++ b/src/java/org/apache/cassandra/cql3/Operation.java
@@ -17,6 +17,7 @@
*/
package org.apache.cassandra.cql3;
+import java.nio.ByteBuffer;
import java.util.List;
import org.apache.cassandra.config.CFMetaData;
@@ -133,7 +134,7 @@ public abstract class Operation
/**
* The name of the column affected by this delete operation.
*/
- public ColumnIdentifier.Raw affectedColumn();
+ public ColumnDefinition.Raw affectedColumn();
/**
* This method validates the operation (i.e. validate it is well typed)
@@ -248,10 +249,10 @@ public abstract class Operation
public static class SetField implements RawUpdate
{
- private final ColumnIdentifier.Raw field;
+ private final FieldIdentifier field;
private final Term.Raw value;
- public SetField(ColumnIdentifier.Raw field, Term.Raw value)
+ public SetField(FieldIdentifier field, Term.Raw value)
{
this.field = field;
this.value = value;
@@ -264,13 +265,12 @@ public abstract class Operation
else if (!receiver.type.isMultiCell())
throw new InvalidRequestException(String.format("Invalid operation (%s) for frozen UDT column %s", toString(receiver), receiver.name));
- ColumnIdentifier fieldIdentifier = field.prepare(cfm);
- int fieldPosition = ((UserType) receiver.type).fieldPosition(fieldIdentifier);
+ int fieldPosition = ((UserType) receiver.type).fieldPosition(field);
if (fieldPosition == -1)
- throw new InvalidRequestException(String.format("UDT column %s does not have a field named %s", receiver.name, fieldIdentifier));
+ throw new InvalidRequestException(String.format("UDT column %s does not have a field named %s", receiver.name, field));
Term val = value.prepare(cfm.ksName, UserTypes.fieldSpecOf(receiver, fieldPosition));
- return new UserTypes.SetterByField(receiver, fieldIdentifier, val);
+ return new UserTypes.SetterByField(receiver, field, val);
}
protected String toString(ColumnSpecification column)
@@ -414,14 +414,14 @@ public abstract class Operation
public static class ColumnDeletion implements RawDeletion
{
- private final ColumnIdentifier.Raw id;
+ private final ColumnDefinition.Raw id;
- public ColumnDeletion(ColumnIdentifier.Raw id)
+ public ColumnDeletion(ColumnDefinition.Raw id)
{
this.id = id;
}
- public ColumnIdentifier.Raw affectedColumn()
+ public ColumnDefinition.Raw affectedColumn()
{
return id;
}
@@ -435,16 +435,16 @@ public abstract class Operation
public static class ElementDeletion implements RawDeletion
{
- private final ColumnIdentifier.Raw id;
+ private final ColumnDefinition.Raw id;
private final Term.Raw element;
- public ElementDeletion(ColumnIdentifier.Raw id, Term.Raw element)
+ public ElementDeletion(ColumnDefinition.Raw id, Term.Raw element)
{
this.id = id;
this.element = element;
}
- public ColumnIdentifier.Raw affectedColumn()
+ public ColumnDefinition.Raw affectedColumn()
{
return id;
}
@@ -474,16 +474,16 @@ public abstract class Operation
public static class FieldDeletion implements RawDeletion
{
- private final ColumnIdentifier.Raw id;
- private final ColumnIdentifier.Raw field;
+ private final ColumnDefinition.Raw id;
+ private final FieldIdentifier field;
- public FieldDeletion(ColumnIdentifier.Raw id, ColumnIdentifier.Raw field)
+ public FieldDeletion(ColumnDefinition.Raw id, FieldIdentifier field)
{
this.id = id;
this.field = field;
}
- public ColumnIdentifier.Raw affectedColumn()
+ public ColumnDefinition.Raw affectedColumn()
{
return id;
}
@@ -495,11 +495,10 @@ public abstract class Operation
else if (!receiver.type.isMultiCell())
throw new InvalidRequestException(String.format("Frozen UDT column %s does not support field deletions", receiver.name));
- ColumnIdentifier fieldIdentifier = field.prepare(cfm);
- if (((UserType) receiver.type).fieldPosition(fieldIdentifier) == -1)
- throw new InvalidRequestException(String.format("UDT column %s does not have a field named %s", receiver.name, fieldIdentifier));
+ if (((UserType) receiver.type).fieldPosition(field) == -1)
+ throw new InvalidRequestException(String.format("UDT column %s does not have a field named %s", receiver.name, field));
- return new UserTypes.DeleterByField(receiver, fieldIdentifier);
+ return new UserTypes.DeleterByField(receiver, field);
}
}
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/4ed00607/src/java/org/apache/cassandra/cql3/Relation.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/Relation.java b/src/java/org/apache/cassandra/cql3/Relation.java
index bc986f6..097b88e 100644
--- a/src/java/org/apache/cassandra/cql3/Relation.java
+++ b/src/java/org/apache/cassandra/cql3/Relation.java
@@ -25,12 +25,11 @@ import org.apache.cassandra.config.ColumnDefinition;
import org.apache.cassandra.cql3.restrictions.Restriction;
import org.apache.cassandra.cql3.statements.Bound;
import org.apache.cassandra.exceptions.InvalidRequestException;
-import org.apache.cassandra.exceptions.UnrecognizedEntityException;
import static org.apache.cassandra.cql3.statements.RequestValidations.invalidRequest;
-public abstract class Relation {
-
+public abstract class Relation
+{
protected Operator relationType;
public Operator operator()
@@ -261,31 +260,11 @@ public abstract class Relation {
}
/**
- * Converts the specified entity into a column definition.
- *
- * @param cfm the column family meta data
- * @param entity the entity to convert
- * @return the column definition corresponding to the specified entity
- * @throws InvalidRequestException if the entity cannot be recognized
- */
- protected final ColumnDefinition toColumnDefinition(CFMetaData cfm,
- ColumnIdentifier.Raw entity) throws InvalidRequestException
- {
- ColumnIdentifier identifier = entity.prepare(cfm);
- ColumnDefinition def = cfm.getColumnDefinition(identifier);
-
- if (def == null)
- throw new UnrecognizedEntityException(identifier, this);
-
- return def;
- }
-
- /**
* Renames an identifier in this Relation, if applicable.
* @param from the old identifier
* @param to the new identifier
* @return this object, if the old identifier is not in the set of entities that this relation covers; otherwise
* a new Relation with "from" replaced by "to" is returned.
*/
- public abstract Relation renameIdentifier(ColumnIdentifier.Raw from, ColumnIdentifier.Raw to);
+ public abstract Relation renameIdentifier(ColumnDefinition.Raw from, ColumnDefinition.Raw to);
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/4ed00607/src/java/org/apache/cassandra/cql3/Sets.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/Sets.java b/src/java/org/apache/cassandra/cql3/Sets.java
index 622bb23..e8617aa 100644
--- a/src/java/org/apache/cassandra/cql3/Sets.java
+++ b/src/java/org/apache/cassandra/cql3/Sets.java
@@ -122,6 +122,18 @@ public abstract class Sets
return AssignmentTestable.TestResult.testAll(keyspace, valueSpec, elements);
}
+ @Override
+ public AbstractType<?> getExactTypeIfKnown(String keyspace)
+ {
+ for (Term.Raw term : elements)
+ {
+ AbstractType<?> type = term.getExactTypeIfKnown(keyspace);
+ if (type != null)
+ return SetType.getInstance(type, false);
+ }
+ return null;
+ }
+
public String getText()
{
return elements.stream().map(Term.Raw::getText).collect(Collectors.joining(", ", "{", "}"));
http://git-wip-us.apache.org/repos/asf/cassandra/blob/4ed00607/src/java/org/apache/cassandra/cql3/SingleColumnRelation.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/SingleColumnRelation.java b/src/java/org/apache/cassandra/cql3/SingleColumnRelation.java
index 3cb07b9..07232d2 100644
--- a/src/java/org/apache/cassandra/cql3/SingleColumnRelation.java
+++ b/src/java/org/apache/cassandra/cql3/SingleColumnRelation.java
@@ -43,12 +43,12 @@ import static org.apache.cassandra.cql3.statements.RequestValidations.invalidReq
*/
public final class SingleColumnRelation extends Relation
{
- private final ColumnIdentifier.Raw entity;
+ private final ColumnDefinition.Raw entity;
private final Term.Raw mapKey;
private final Term.Raw value;
private final List<Term.Raw> inValues;
- private SingleColumnRelation(ColumnIdentifier.Raw entity, Term.Raw mapKey, Operator type, Term.Raw value, List<Term.Raw> inValues)
+ private SingleColumnRelation(ColumnDefinition.Raw entity, Term.Raw mapKey, Operator type, Term.Raw value, List<Term.Raw> inValues)
{
this.entity = entity;
this.mapKey = mapKey;
@@ -68,7 +68,7 @@ public final class SingleColumnRelation extends Relation
* @param type the type that describes how this entity relates to the value.
* @param value the value being compared.
*/
- public SingleColumnRelation(ColumnIdentifier.Raw entity, Term.Raw mapKey, Operator type, Term.Raw value)
+ public SingleColumnRelation(ColumnDefinition.Raw entity, Term.Raw mapKey, Operator type, Term.Raw value)
{
this(entity, mapKey, type, value, null);
}
@@ -80,7 +80,7 @@ public final class SingleColumnRelation extends Relation
* @param type the type that describes how this entity relates to the value.
* @param value the value being compared.
*/
- public SingleColumnRelation(ColumnIdentifier.Raw entity, Operator type, Term.Raw value)
+ public SingleColumnRelation(ColumnDefinition.Raw entity, Operator type, Term.Raw value)
{
this(entity, null, type, value);
}
@@ -95,12 +95,12 @@ public final class SingleColumnRelation extends Relation
return inValues;
}
- public static SingleColumnRelation createInRelation(ColumnIdentifier.Raw entity, List<Term.Raw> inValues)
+ public static SingleColumnRelation createInRelation(ColumnDefinition.Raw entity, List<Term.Raw> inValues)
{
return new SingleColumnRelation(entity, null, Operator.IN, null, inValues);
}
- public ColumnIdentifier.Raw getEntity()
+ public ColumnDefinition.Raw getEntity()
{
return entity;
}
@@ -134,7 +134,7 @@ public final class SingleColumnRelation extends Relation
}
}
- public Relation renameIdentifier(ColumnIdentifier.Raw from, ColumnIdentifier.Raw to)
+ public Relation renameIdentifier(ColumnDefinition.Raw from, ColumnDefinition.Raw to)
{
return entity.equals(from)
? new SingleColumnRelation(to, mapKey, operator(), value, inValues)
@@ -158,7 +158,7 @@ public final class SingleColumnRelation extends Relation
protected Restriction newEQRestriction(CFMetaData cfm,
VariableSpecifications boundNames) throws InvalidRequestException
{
- ColumnDefinition columnDef = toColumnDefinition(cfm, entity);
+ ColumnDefinition columnDef = entity.prepare(cfm);
if (mapKey == null)
{
Term term = toTerm(toReceivers(columnDef, cfm.isDense()), value, cfm.ksName, boundNames);
@@ -174,7 +174,7 @@ public final class SingleColumnRelation extends Relation
protected Restriction newINRestriction(CFMetaData cfm,
VariableSpecifications boundNames) throws InvalidRequestException
{
- ColumnDefinition columnDef = toColumnDefinition(cfm, entity);
+ ColumnDefinition columnDef = entity.prepare(cfm);
List<? extends ColumnSpecification> receivers = toReceivers(columnDef, cfm.isDense());
List<Term> terms = toTerms(receivers, inValues, cfm.ksName, boundNames);
if (terms == null)
@@ -191,7 +191,7 @@ public final class SingleColumnRelation extends Relation
Bound bound,
boolean inclusive) throws InvalidRequestException
{
- ColumnDefinition columnDef = toColumnDefinition(cfm, entity);
+ ColumnDefinition columnDef = entity.prepare(cfm);
Term term = toTerm(toReceivers(columnDef, cfm.isDense()), value, cfm.ksName, boundNames);
return new SingleColumnRestriction.SliceRestriction(columnDef, bound, inclusive, term);
}
@@ -201,7 +201,7 @@ public final class SingleColumnRelation extends Relation
VariableSpecifications boundNames,
boolean isKey) throws InvalidRequestException
{
- ColumnDefinition columnDef = toColumnDefinition(cfm, entity);
+ ColumnDefinition columnDef = entity.prepare(cfm);
Term term = toTerm(toReceivers(columnDef, cfm.isDense()), value, cfm.ksName, boundNames);
return new SingleColumnRestriction.ContainsRestriction(columnDef, term, isKey);
}
@@ -210,7 +210,7 @@ public final class SingleColumnRelation extends Relation
protected Restriction newIsNotRestriction(CFMetaData cfm,
VariableSpecifications boundNames) throws InvalidRequestException
{
- ColumnDefinition columnDef = toColumnDefinition(cfm, entity);
+ ColumnDefinition columnDef = entity.prepare(cfm);
// currently enforced by the grammar
assert value == Constants.NULL_LITERAL : "Expected null literal for IS NOT relation: " + this.toString();
return new SingleColumnRestriction.IsNotNullRestriction(columnDef);
@@ -222,7 +222,7 @@ public final class SingleColumnRelation extends Relation
if (mapKey != null)
throw invalidRequest("%s can't be used with collections.", operator());
- ColumnDefinition columnDef = toColumnDefinition(cfm, entity);
+ ColumnDefinition columnDef = entity.prepare(cfm);
Term term = toTerm(toReceivers(columnDef, cfm.isDense()), value, cfm.ksName, boundNames);
return new SingleColumnRestriction.LikeRestriction(columnDef, operator, term);
http://git-wip-us.apache.org/repos/asf/cassandra/blob/4ed00607/src/java/org/apache/cassandra/cql3/Term.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/Term.java b/src/java/org/apache/cassandra/cql3/Term.java
index 5ae9c18..2c2eba6 100644
--- a/src/java/org/apache/cassandra/cql3/Term.java
+++ b/src/java/org/apache/cassandra/cql3/Term.java
@@ -18,11 +18,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.cql3.functions.Function;
+import org.apache.cassandra.db.marshal.AbstractType;
import org.apache.cassandra.exceptions.InvalidRequestException;
/**
@@ -100,6 +99,17 @@ public interface Term
*/
public abstract String getText();
+ /**
+ * The type of the {@code term} if it can be infered.
+ *
+ * @param keyspace the keyspace on which the statement containing this term is on.
+ * @return the type of this {@code Term} if inferrable, or {@code null}
+ * otherwise (for instance, the type isn't inferable for a bind marker. Even for
+ * literals, the exact type is not inferrable since they are valid for many
+ * different types and so this will return {@code null} too).
+ */
+ public abstract AbstractType<?> getExactTypeIfKnown(String keyspace);
+
@Override
public String toString()
{
http://git-wip-us.apache.org/repos/asf/cassandra/blob/4ed00607/src/java/org/apache/cassandra/cql3/TokenRelation.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/TokenRelation.java b/src/java/org/apache/cassandra/cql3/TokenRelation.java
index 8b8b9ce..42464ef 100644
--- a/src/java/org/apache/cassandra/cql3/TokenRelation.java
+++ b/src/java/org/apache/cassandra/cql3/TokenRelation.java
@@ -47,11 +47,11 @@ import static org.apache.cassandra.cql3.statements.RequestValidations.invalidReq
*/
public final class TokenRelation extends Relation
{
- private final List<ColumnIdentifier.Raw> entities;
+ private final List<ColumnDefinition.Raw> entities;
private final Term.Raw value;
- public TokenRelation(List<ColumnIdentifier.Raw> entities, Operator type, Term.Raw value)
+ public TokenRelation(List<ColumnDefinition.Raw> entities, Operator type, Term.Raw value)
{
this.entities = entities;
this.relationType = type;
@@ -128,12 +128,12 @@ public final class TokenRelation extends Relation
return term;
}
- public Relation renameIdentifier(ColumnIdentifier.Raw from, ColumnIdentifier.Raw to)
+ public Relation renameIdentifier(ColumnDefinition.Raw from, ColumnDefinition.Raw to)
{
if (!entities.contains(from))
return this;
- List<ColumnIdentifier.Raw> newEntities = entities.stream().map(e -> e.equals(from) ? to : e).collect(Collectors.toList());
+ List<ColumnDefinition.Raw> newEntities = entities.stream().map(e -> e.equals(from) ? to : e).collect(Collectors.toList());
return new TokenRelation(newEntities, operator(), value);
}
@@ -152,11 +152,9 @@ public final class TokenRelation extends Relation
*/
private List<ColumnDefinition> getColumnDefinitions(CFMetaData cfm) throws InvalidRequestException
{
- List<ColumnDefinition> columnDefs = new ArrayList<>();
- for ( ColumnIdentifier.Raw raw : entities)
- {
- columnDefs.add(toColumnDefinition(cfm, raw));
- }
+ List<ColumnDefinition> columnDefs = new ArrayList<>(entities.size());
+ for ( ColumnDefinition.Raw raw : entities)
+ columnDefs.add(raw.prepare(cfm));
return columnDefs;
}