http://git-wip-us.apache.org/repos/asf/cassandra/blob/26217071/src/java/org/apache/cassandra/cql/Cql.g ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql/Cql.g b/src/java/org/apache/cassandra/cql/Cql.g deleted file mode 100644 index 3c41f44..0000000 --- a/src/java/org/apache/cassandra/cql/Cql.g +++ /dev/null @@ -1,656 +0,0 @@ - -/* - * - * 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. - * - */ - -grammar Cql; - -options { - language = Java; -} - -@header { - package org.apache.cassandra.cql; - import java.util.Map; - import java.util.HashMap; - import java.util.Collections; - import java.util.List; - import java.util.ArrayList; - import org.apache.cassandra.exceptions.SyntaxException; - import org.apache.cassandra.utils.Pair; - import org.apache.cassandra.db.ConsistencyLevel; - - import static org.apache.cassandra.cql.AlterTableStatement.OperationType; -} - -@members { - private List<String> recognitionErrors = new ArrayList<String>(); - private int currentBindMarkerIdx = -1; - - public void displayRecognitionError(String[] tokenNames, RecognitionException e) - { - String hdr = getErrorHeader(e); - String msg = getErrorMessage(e, tokenNames); - recognitionErrors.add(hdr + " " + msg); - } - - public List<String> getRecognitionErrors() - { - return recognitionErrors; - } - - public void throwLastRecognitionError() throws SyntaxException - { - if (recognitionErrors.size() > 0) - throw new SyntaxException(recognitionErrors.get((recognitionErrors.size()-1))); - } - - // used by UPDATE of the counter columns to validate if '-' was supplied by user - public void validateMinusSupplied(Object op, final Term value, IntStream stream) throws MissingTokenException - { - if (op == null && Long.parseLong(value.getText()) > 0) - throw new MissingTokenException(102, stream, value); - } -} - -@lexer::header { - package org.apache.cassandra.cql; - import org.apache.cassandra.exceptions.SyntaxException; -} - -@lexer::members { - List<Token> tokens = new ArrayList<Token>(); - - public void emit(Token token) { - state.token = token; - tokens.add(token); - } - - public Token nextToken() { - super.nextToken(); - if (tokens.size() == 0) - return Token.EOF_TOKEN; - return tokens.remove(0); - } - - private List<String> recognitionErrors = new ArrayList<String>(); - - public void displayRecognitionError(String[] tokenNames, RecognitionException e) - { - String hdr = getErrorHeader(e); - String msg = getErrorMessage(e, tokenNames); - recognitionErrors.add(hdr + " " + msg); - } - - public List<String> getRecognitionErrors() - { - return recognitionErrors; - } - - public void throwLastRecognitionError() throws SyntaxException - { - if (recognitionErrors.size() > 0) - throw new SyntaxException(recognitionErrors.get((recognitionErrors.size()-1))); - } -} - -query returns [CQLStatement stmnt] - : selectStatement { $stmnt = new CQLStatement(StatementType.SELECT, $selectStatement.expr, currentBindMarkerIdx); } - | insertStatement endStmnt { $stmnt = new CQLStatement(StatementType.INSERT, $insertStatement.expr, currentBindMarkerIdx); } - | updateStatement endStmnt { $stmnt = new CQLStatement(StatementType.UPDATE, $updateStatement.expr, currentBindMarkerIdx); } - | batchStatement { $stmnt = new CQLStatement(StatementType.BATCH, $batchStatement.expr, currentBindMarkerIdx); } - | useStatement { $stmnt = new CQLStatement(StatementType.USE, $useStatement.keyspace, currentBindMarkerIdx); } - | truncateStatement { $stmnt = new CQLStatement(StatementType.TRUNCATE, $truncateStatement.cf, currentBindMarkerIdx); } - | deleteStatement endStmnt { $stmnt = new CQLStatement(StatementType.DELETE, $deleteStatement.expr, currentBindMarkerIdx); } - | createKeyspaceStatement { $stmnt = new CQLStatement(StatementType.CREATE_KEYSPACE, $createKeyspaceStatement.expr, currentBindMarkerIdx); } - | createColumnFamilyStatement { $stmnt = new CQLStatement(StatementType.CREATE_COLUMNFAMILY, $createColumnFamilyStatement.expr, currentBindMarkerIdx); } - | createIndexStatement { $stmnt = new CQLStatement(StatementType.CREATE_INDEX, $createIndexStatement.expr, currentBindMarkerIdx); } - | dropIndexStatement { $stmnt = new CQLStatement(StatementType.DROP_INDEX, $dropIndexStatement.expr, currentBindMarkerIdx); } - | dropKeyspaceStatement { $stmnt = new CQLStatement(StatementType.DROP_KEYSPACE, $dropKeyspaceStatement.ksp, currentBindMarkerIdx); } - | dropColumnFamilyStatement { $stmnt = new CQLStatement(StatementType.DROP_COLUMNFAMILY, $dropColumnFamilyStatement.cfam, currentBindMarkerIdx); } - | alterTableStatement { $stmnt = new CQLStatement(StatementType.ALTER_TABLE, $alterTableStatement.expr, currentBindMarkerIdx); } - ; - -// USE <KEYSPACE>; -useStatement returns [String keyspace] - : K_USE name=( IDENT | INTEGER | STRING_LITERAL ) { $keyspace = $name.text; } endStmnt - ; - -/** - * SELECT - * (REVERSED)? <expression> - * FROM - * <CF> - * USING - * CONSISTENCY <LEVEL> - * WHERE - * KEY = "key1" AND KEY = "key2" AND - * COL > 1 AND COL < 100 - * LIMIT <NUMBER>; - */ -selectStatement returns [SelectStatement expr] - : { - int numRecords = 10000; - SelectExpression expression = null; - boolean isCountOp = false; - ConsistencyLevel cLevel = ConsistencyLevel.ONE; - } - K_SELECT - ( s1=selectExpression { expression = s1; } - | K_COUNT '(' s2=selectExpression ')' { expression = s2; isCountOp = true; } - ) - K_FROM (keyspace=(IDENT | STRING_LITERAL | INTEGER) '.')? columnFamily=( IDENT | STRING_LITERAL | INTEGER ) - ( K_USING K_CONSISTENCY K_LEVEL { cLevel = ConsistencyLevel.valueOf($K_LEVEL.text.toUpperCase()); } )? - ( K_WHERE whereClause )? - ( K_LIMIT rows=INTEGER { numRecords = Integer.parseInt($rows.text); } )? - endStmnt - { - return new SelectStatement(expression, - isCountOp, - $keyspace.text, - $columnFamily.text, - cLevel, - $whereClause.clause, - numRecords); - } - ; - -// [FIRST n] [REVERSED] name1[[[,name2],nameN],...] -// [FIRST n] [REVERSED] name1..nameN -selectExpression returns [SelectExpression expr] - : { - int count = 10000; - boolean reversed = false; - boolean hasFirstSet = false; - } - ( K_FIRST { hasFirstSet = true; } cols=INTEGER { count = Integer.parseInt($cols.text); } )? - ( K_REVERSED { reversed = true; } )? - ( first=term { $expr = new SelectExpression(first, count, reversed, hasFirstSet); } - (',' next=term { $expr.and(next); })* - | start=term RANGEOP finish=term { $expr = new SelectExpression(start, finish, count, reversed, false, hasFirstSet); } - | '\*' { $expr = new SelectExpression(new Term(), new Term(), count, reversed, true, hasFirstSet); } - ) - ; - -// relation [[AND relation] ...] -whereClause returns [WhereClause clause] - @init { - WhereClause inClause = new WhereClause(); - } - : first=relation { $clause = new WhereClause(first); } - (K_AND next=relation { $clause.and(next); })* - | key_alias=term { inClause.setKeyAlias(key_alias.getText()); } - K_IN '(' f1=term { inClause.andKeyEquals(f1); } - (',' fN=term { inClause.andKeyEquals(fN); } )* ')' - { inClause.setMultiKey(true); $clause = inClause; } - ; - -/** - * INSERT INTO - * <CF> - * (KEY, <column>, <column>, ...) - * VALUES - * (<key>, <value>, <value>, ...) - * (USING - * CONSISTENCY <level> - * (AND TIMESTAMP <long>)? - * )?; - * - * Consistency level is set to ONE by default - */ -insertStatement returns [UpdateStatement expr] - : { - Attributes attrs = new Attributes(); - - List<Term> columnNames = new ArrayList<Term>(); - List<Term> columnValues = new ArrayList<Term>(); - } - K_INSERT K_INTO (keyspace=(IDENT | STRING_LITERAL | INTEGER) '.')? columnFamily=( IDENT | STRING_LITERAL | INTEGER ) - '(' key_alias=term ( ',' column_name=term { columnNames.add($column_name.item); } )+ ')' - K_VALUES - '(' key=term ( ',' column_value=term { columnValues.add($column_value.item); })+ ')' - ( usingClause[attrs] )? - { - return new UpdateStatement($keyspace.text, $columnFamily.text, key_alias.getText(), columnNames, columnValues, Collections.singletonList(key), attrs); - } - ; - -usingClause[Attributes attrs] - : K_USING usingClauseObjective[attrs] ( K_AND? usingClauseObjective[attrs] )* - ; - -usingClauseDelete[Attributes attrs] - : K_USING usingClauseDeleteObjective[attrs] ( K_AND? usingClauseDeleteObjective[attrs] )* - ; - -usingClauseDeleteObjective[Attributes attrs] - : K_CONSISTENCY K_LEVEL { attrs.setConsistencyLevel(ConsistencyLevel.valueOf($K_LEVEL.text.toUpperCase())); } - | K_TIMESTAMP ts=INTEGER { attrs.setTimestamp(Long.valueOf($ts.text)); } - ; - -usingClauseObjective[Attributes attrs] - : usingClauseDeleteObjective[attrs] - | K_TTL t=INTEGER { attrs.setTimeToLive(Integer.parseInt($t.text)); } - ; - -/** - * BEGIN BATCH [USING CONSISTENCY <LVL>] - * UPDATE <CF> SET name1 = value1 WHERE KEY = keyname1; - * UPDATE <CF> SET name2 = value2 WHERE KEY = keyname2; - * UPDATE <CF> SET name3 = value3 WHERE KEY = keyname3; - * ... - * APPLY BATCH - * - * OR - * - * BEGIN BATCH [USING CONSISTENCY <LVL>] - * INSERT INTO <CF> (KEY, <name>) VALUES ('<key>', '<value>'); - * INSERT INTO <CF> (KEY, <name>) VALUES ('<key>', '<value>'); - * ... - * APPLY BATCH - * - * OR - * - * BEGIN BATCH [USING CONSISTENCY <LVL>] - * DELETE name1, name2 FROM <CF> WHERE key = <key> - * DELETE name3, name4 FROM <CF> WHERE key = <key> - * ... - * APPLY BATCH - */ -batchStatement returns [BatchStatement expr] - : { - Attributes attrs = new Attributes(); - attrs.setConsistencyLevel(ConsistencyLevel.ONE); - - List<AbstractModification> statements = new ArrayList<AbstractModification>(); - } - K_BEGIN K_BATCH ( usingClause[attrs] )? - s1=batchStatementObjective ';'? { statements.add(s1); } ( sN=batchStatementObjective ';'? { statements.add(sN); } )* - K_APPLY K_BATCH endStmnt - { - return new BatchStatement(statements, attrs); - } - ; - -batchStatementObjective returns [AbstractModification statement] - : i=insertStatement { $statement = i; } - | u=updateStatement { $statement = u; } - | d=deleteStatement { $statement = d; } - ; - -/** - * UPDATE - * <CF> - * (USING - * CONSISTENCY.ONE - * (AND TIMESTAMP <long>)? - * )? - * SET - * name1 = value1, - * name2 = value2 - * WHERE - * KEY = keyname; - */ -updateStatement returns [UpdateStatement expr] - : { - Attributes attrs = new Attributes(); - Map<Term, Operation> columns = new HashMap<Term, Operation>(); - List<Term> keyList = null; - } - K_UPDATE (keyspace=(IDENT | STRING_LITERAL | INTEGER) '.')? columnFamily=( IDENT | STRING_LITERAL | INTEGER ) - ( usingClause[attrs] )? - K_SET termPairWithOperation[columns] (',' termPairWithOperation[columns])* - K_WHERE ( key_alias=term ('=' key=term { keyList = Collections.singletonList(key); } - | - K_IN '(' keys=termList { keyList = $keys.items; } ')' )) - { - return new UpdateStatement($keyspace.text, $columnFamily.text, key_alias.getText(), columns, keyList, attrs); - } - ; - -/** - * DELETE - * name1, name2 - * FROM - * <CF> - * USING - * CONSISTENCY.<LVL> - * WHERE - * KEY = keyname; - */ -deleteStatement returns [DeleteStatement expr] - : { - Attributes attrs = new Attributes(); - List<Term> keyList = null; - List<Term> columnsList = Collections.emptyList(); - } - K_DELETE - ( cols=termList { columnsList = $cols.items; })? - K_FROM (keyspace=(IDENT | STRING_LITERAL | INTEGER) '.')? columnFamily=( IDENT | STRING_LITERAL | INTEGER ) - ( usingClauseDelete[attrs] )? - ( K_WHERE key_alias=term ('=' key=term { keyList = Collections.singletonList(key); } - | K_IN '(' keys=termList { keyList = $keys.items; } ')') - )? - { - return new DeleteStatement(columnsList, $keyspace.text, $columnFamily.text, key_alias.getText(), keyList, attrs); - } - ; - - - -/** CREATE KEYSPACE <KEYSPACE> WITH attr1 = value1 AND attr2 = value2; */ -createKeyspaceStatement returns [CreateKeyspaceStatement expr] - : { - Map<String, String> attrs = new HashMap<String, String>(); - } - K_CREATE K_KEYSPACE keyspace=( IDENT | STRING_LITERAL | INTEGER ) - K_WITH a1=( COMPIDENT | IDENT ) '=' v1=( STRING_LITERAL | INTEGER | IDENT ) { attrs.put($a1.text, $v1.text); } - ( K_AND aN=( COMPIDENT | IDENT ) '=' vN=( STRING_LITERAL | INTEGER | IDENT ) { attrs.put($aN.text, $vN.text); } )* - endStmnt - { - return new CreateKeyspaceStatement($keyspace.text, attrs); - } - ; - -/** - * CREATE COLUMNFAMILY <CF> ( - * <name1> <type>, - * <name2> <type>, - * <name3> <type> - * ) WITH comparator = <type> [AND ...]; - */ -createColumnFamilyStatement returns [CreateColumnFamilyStatement expr] - : K_CREATE K_COLUMNFAMILY name=( IDENT | STRING_LITERAL | INTEGER ) { $expr = new CreateColumnFamilyStatement($name.text); } - ( '(' createCfamColumns[expr] ( ',' createCfamColumns[expr] )* ')' )? - ( K_WITH prop1=(COMPIDENT | IDENT) '=' arg1=createCfamKeywordArgument { $expr.addProperty($prop1.text, $arg1.arg); } - ( K_AND propN=(COMPIDENT | IDENT) '=' argN=createCfamKeywordArgument { $expr.addProperty($propN.text, $argN.arg); } )* - )? - endStmnt - ; - -createCfamColumns[CreateColumnFamilyStatement expr] - : n=term v=createCfamColumnValidator { $expr.addColumn(n, $v.validator); } - | k=term v=createCfamColumnValidator K_PRIMARY K_KEY { $expr.setKeyAlias(k.getText()); $expr.setKeyType($v.validator); } - ; - -createCfamColumnValidator returns [String validator] - : comparatorType { $validator = $comparatorType.text; } - | STRING_LITERAL { $validator = $STRING_LITERAL.text; } - ; - -createCfamKeywordArgument returns [String arg] - : comparatorType { $arg = $comparatorType.text; } - | value=( STRING_LITERAL | IDENT | INTEGER | FLOAT ) { $arg = $value.text; } - ; - -/** CREATE INDEX [indexName] ON columnFamily (columnName); */ -createIndexStatement returns [CreateIndexStatement expr] - : K_CREATE K_INDEX (idxName=IDENT)? K_ON cf=( IDENT | STRING_LITERAL | INTEGER ) '(' columnName=term ')' endStmnt - { $expr = new CreateIndexStatement($idxName.text, $cf.text, columnName); } - ; -/** - * DROP INDEX ON <CF>.<COLUMN_OR_INDEX_NAME> - * DROP INDEX <INDEX_NAME> - */ -dropIndexStatement returns [DropIndexStatement expr] - : - K_DROP K_INDEX index=( IDENT | STRING_LITERAL | INTEGER ) endStmnt - { $expr = new DropIndexStatement($index.text); } - ; - -/** DROP KEYSPACE <KSP>; */ -dropKeyspaceStatement returns [String ksp] - : K_DROP K_KEYSPACE name=( IDENT | STRING_LITERAL | INTEGER ) endStmnt { $ksp = $name.text; } - ; - - -alterTableStatement returns [AlterTableStatement expr] - : - { - OperationType type = null; - String columnFamily = null, columnName = null, validator = null; - Map<String, String> propertyMap = null; - } - K_ALTER K_COLUMNFAMILY name=( IDENT | STRING_LITERAL | INTEGER ) { columnFamily = $name.text; } - ( K_ALTER { type = OperationType.ALTER; } - (col=( IDENT | STRING_LITERAL | INTEGER ) { columnName = $col.text; }) - K_TYPE alterValidator=comparatorType { validator = $alterValidator.text; } - | K_ADD { type = OperationType.ADD; } - (col=( IDENT | STRING_LITERAL | INTEGER ) { columnName = $col.text; }) - addValidator=comparatorType { validator = $addValidator.text; } - | K_DROP { type = OperationType.DROP; } - (col=( IDENT | STRING_LITERAL | INTEGER ) { columnName = $col.text; }) - | K_WITH { type = OperationType.OPTS; propertyMap = new HashMap<String, String>(); } - prop1=(COMPIDENT | IDENT) '=' arg1=createCfamKeywordArgument { propertyMap.put($prop1.text, $arg1.arg); } - ( K_AND propN=(COMPIDENT | IDENT) '=' argN=createCfamKeywordArgument { propertyMap.put($propN.text, $argN.arg); } )* ) - endStmnt - { - $expr = new AlterTableStatement(columnFamily, type, columnName, validator, propertyMap); - } - ; - -/** DROP COLUMNFAMILY <CF>; */ -dropColumnFamilyStatement returns [String cfam] - : K_DROP K_COLUMNFAMILY name=( IDENT | STRING_LITERAL | INTEGER ) endStmnt { $cfam = $name.text; } - ; - -comparatorType - : 'blob' | 'ascii' | 'text' | 'varchar' | 'int' | 'varint' | 'bigint' | 'uuid' | 'counter' | 'boolean' | 'timestamp' | 'float' | 'double' | 'decimal' - ; - -term returns [Term item] - : (( t=K_KEY | t=STRING_LITERAL | t=INTEGER | t=UUID | t=IDENT | t=FLOAT ) { $item = new Term($t.text, $t.type); } - | t=QMARK { $item = new Term($t.text, $t.type, ++currentBindMarkerIdx); } - ) - ; - -termList returns [List<Term> items] - : { $items = new ArrayList<Term>(); } - t1=term { $items.add(t1); } (',' tN=term { $items.add(tN); })* - ; - -// term = term -termPair[Map<Term, Term> columns] - : key=term '=' value=term { columns.put(key, value); } - ; - -intTerm returns [Term integer] - : t=INTEGER { $integer = new Term($t.text, $t.type); } - ; - -termPairWithOperation[Map<Term, Operation> columns] - : key=term '=' (value=term { columns.put(key, new Operation(value)); } - | c=term ( '+' v=term { columns.put(key, new Operation(c, org.apache.cassandra.cql.Operation.OperationType.PLUS, v)); } - | op='-'? v=intTerm - { validateMinusSupplied(op, v, input); - if (op != null) v = new Term(-(Long.valueOf(v.getText())), v.getType()); - columns.put(key, new Operation(c, org.apache.cassandra.cql.Operation.OperationType.MINUS, v)); } )) - ; - -// Note: ranges are inclusive so >= and >, and < and <= all have the same semantics. -relation returns [Relation rel] - : name=term type=('=' | '<' | '<=' | '>=' | '>') t=term - { return new Relation($name.item, $type.text, $t.item); } - ; - -// TRUNCATE <CF>; -truncateStatement returns [Pair<String,String> cf] - : K_TRUNCATE (keyspace=( IDENT | STRING_LITERAL | INTEGER ) '.')? columnFamily=( IDENT | STRING_LITERAL | INTEGER ) { $cf = Pair.create($keyspace.text, $columnFamily.text); } endStmnt - ; - -endStmnt - : ';'? EOF - ; - - -// Case-insensitive keywords -K_SELECT: S E L E C T; -K_FROM: F R O M; -K_WHERE: W H E R E; -K_AND: A N D; -K_KEY: K E Y; -K_INSERT: I N S E R T; -K_UPDATE: U P D A T E; -K_WITH: W I T H; -K_LIMIT: L I M I T; -K_USING: U S I N G; -K_CONSISTENCY: C O N S I S T E N C Y; -K_LEVEL: ( O N E - | Q U O R U M - | A L L - | A N Y - | L O C A L '_' Q U O R U M - | E A C H '_' Q U O R U M - | T W O - | T H R E E - ) - ; -K_USE: U S E; -K_FIRST: F I R S T; -K_REVERSED: R E V E R S E D; -K_COUNT: C O U N T; -K_SET: S E T; -K_BEGIN: B E G I N; -K_APPLY: A P P L Y; -K_BATCH: B A T C H; -K_TRUNCATE: T R U N C A T E; -K_DELETE: D E L E T E; -K_IN: I N; -K_CREATE: C R E A T E; -K_KEYSPACE: ( K E Y S P A C E - | S C H E M A ); -K_COLUMNFAMILY:( C O L U M N F A M I L Y - | T A B L E ); -K_INDEX: I N D E X; -K_ON: O N; -K_DROP: D R O P; -K_PRIMARY: P R I M A R Y; -K_INTO: I N T O; -K_VALUES: V A L U E S; -K_TIMESTAMP: T I M E S T A M P; -K_TTL: T T L; -K_ALTER: A L T E R; -K_ADD: A D D; -K_TYPE: T Y P E; - -// Case-insensitive alpha characters -fragment A: ('a'|'A'); -fragment B: ('b'|'B'); -fragment C: ('c'|'C'); -fragment D: ('d'|'D'); -fragment E: ('e'|'E'); -fragment F: ('f'|'F'); -fragment G: ('g'|'G'); -fragment H: ('h'|'H'); -fragment I: ('i'|'I'); -fragment J: ('j'|'J'); -fragment K: ('k'|'K'); -fragment L: ('l'|'L'); -fragment M: ('m'|'M'); -fragment N: ('n'|'N'); -fragment O: ('o'|'O'); -fragment P: ('p'|'P'); -fragment Q: ('q'|'Q'); -fragment R: ('r'|'R'); -fragment S: ('s'|'S'); -fragment T: ('t'|'T'); -fragment U: ('u'|'U'); -fragment V: ('v'|'V'); -fragment W: ('w'|'W'); -fragment X: ('x'|'X'); -fragment Y: ('y'|'Y'); -fragment Z: ('z'|'Z'); - -STRING_LITERAL - : '\'' - { StringBuilder b = new StringBuilder(); } - ( c=~('\'') { b.appendCodePoint(c);} - | '\'' '\'' { b.appendCodePoint('\'');} - )* - '\'' - { setText(b.toString()); } - ; - -fragment DIGIT - : '0'..'9' - ; - -fragment LETTER - : ('A'..'Z' | 'a'..'z') - ; - -fragment HEX - : ('A'..'F' | 'a'..'f' | '0'..'9') - ; - -RANGEOP - : '..' - ; - -INTEGER - : '-'? DIGIT+ - ; - -QMARK - : '?' - ; - - -/* Normally a lexer only emits one token at a time, but ours is tricked out - * to support multiple (see @lexer::members near the top of the grammar). - */ -FLOAT - : d=INTEGER r=RANGEOP - { - $d.setType(INTEGER); - emit($d); - $r.setType(RANGEOP); - emit($r); - } - | INTEGER '.' INTEGER - ; - -IDENT - : LETTER (LETTER | DIGIT | '_')* - ; - -COMPIDENT - : IDENT ( ':' (IDENT | INTEGER))* - ; - -UUID - : HEX HEX HEX HEX HEX HEX HEX HEX '-' - HEX HEX HEX HEX '-' - HEX HEX HEX HEX '-' - HEX HEX HEX HEX '-' - HEX HEX HEX HEX HEX HEX HEX HEX HEX HEX HEX HEX - ; - -WS - : (' ' | '\t' | '\n' | '\r')+ { $channel = HIDDEN; } - ; - -COMMENT - : ('--' | '//') .* ('\n'|'\r') { $channel = HIDDEN; } - ; - -MULTILINE_COMMENT - : '/*' .* '*/' { $channel = HIDDEN; } - ;
http://git-wip-us.apache.org/repos/asf/cassandra/blob/26217071/src/java/org/apache/cassandra/cql/CreateColumnFamilyStatement.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql/CreateColumnFamilyStatement.java b/src/java/org/apache/cassandra/cql/CreateColumnFamilyStatement.java deleted file mode 100644 index e568dd7..0000000 --- a/src/java/org/apache/cassandra/cql/CreateColumnFamilyStatement.java +++ /dev/null @@ -1,253 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.cassandra.cql; - -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.apache.cassandra.config.CFMetaData; -import org.apache.cassandra.config.ColumnDefinition; -import org.apache.cassandra.db.composites.SimpleDenseCellNameType; -import org.apache.cassandra.db.ColumnFamilyType; -import org.apache.cassandra.db.marshal.AbstractType; -import org.apache.cassandra.db.marshal.TypeParser; -import org.apache.cassandra.exceptions.ConfigurationException; -import org.apache.cassandra.exceptions.InvalidRequestException; -import org.apache.cassandra.exceptions.SyntaxException; -import org.apache.cassandra.utils.ByteBufferUtil; -import org.apache.cassandra.io.compress.CompressionParameters; - -/** A <code>CREATE COLUMNFAMILY</code> parsed from a CQL query statement. */ -public class CreateColumnFamilyStatement -{ - private final String name; - private final Map<Term, String> columns = new HashMap<Term, String>(); - private final List<String> keyValidator = new ArrayList<String>(); - private ByteBuffer keyAlias = null; - private final CFPropDefs cfProps = new CFPropDefs(); - - public CreateColumnFamilyStatement(String name) - { - this.name = name; - } - - /** Perform validation of parsed params */ - private void validate(List<ByteBuffer> variables) throws InvalidRequestException - { - // Ensure that exactly one key has been specified. - if (keyValidator.size() < 1) - throw new InvalidRequestException("You must specify a PRIMARY KEY"); - else if (keyValidator.size() > 1) - throw new InvalidRequestException("You may only specify one PRIMARY KEY"); - - AbstractType<?> comparator; - - try - { - cfProps.validate(); - comparator = cfProps.getComparator(); - } - catch (ConfigurationException e) - { - throw new InvalidRequestException(e.toString()); - } - catch (SyntaxException e) - { - throw new InvalidRequestException(e.toString()); - } - - for (Map.Entry<Term, String> column : columns.entrySet()) - { - ByteBuffer name = column.getKey().getByteBuffer(comparator, variables); - - if (keyAlias != null && keyAlias.equals(name)) - throw new InvalidRequestException("Invalid column name: " - + column.getKey().getText() - + ", because it equals to the key_alias."); - - } - } - - /** Map a column name to a validator for its value */ - public void addColumn(Term term, String comparator) - { - columns.put(term, comparator); - } - - public void setKeyType(String validator) - { - keyValidator.add(validator); - } - - public String getKeyType() - { - return keyValidator.get(0); - } - - public void setKeyAlias(String alias) - { - // if we got KEY in input we don't need to set an alias - if (!alias.toUpperCase().equals("KEY")) - keyAlias = ByteBufferUtil.bytes(alias); - } - - /** Map a keyword to the corresponding value */ - public void addProperty(String name, String value) - { - cfProps.addProperty(name, value); - } - - /** Name of the column family to create */ - public String getName() - { - return name; - } - - // Column definitions - private List<ColumnDefinition> getColumns(CFMetaData cfm) throws InvalidRequestException - { - List<ColumnDefinition> columnDefs = new ArrayList<>(columns.size()); - - for (Map.Entry<Term, String> col : columns.entrySet()) - { - try - { - ByteBuffer columnName = cfm.comparator.asAbstractType().fromStringCQL2(col.getKey().getText()); - String validatorClassName = CFPropDefs.comparators.containsKey(col.getValue()) - ? CFPropDefs.comparators.get(col.getValue()) - : col.getValue(); - AbstractType<?> validator = TypeParser.parse(validatorClassName); - columnDefs.add(ColumnDefinition.regularDef(cfm, columnName, validator, null)); - } - catch (ConfigurationException e) - { - InvalidRequestException ex = new InvalidRequestException(e.toString()); - ex.initCause(e); - throw ex; - } - catch (SyntaxException e) - { - InvalidRequestException ex = new InvalidRequestException(e.toString()); - ex.initCause(e); - throw ex; - } - } - - return columnDefs; - } - - /** - * Returns a CFMetaData instance based on the parameters parsed from this - * <code>CREATE</code> statement, or defaults where applicable. - * - * @param keyspace keyspace to apply this column family to - * @return a CFMetaData instance corresponding to the values parsed from this statement - * @throws InvalidRequestException on failure to validate parsed parameters - */ - public CFMetaData getCFMetaData(String keyspace, List<ByteBuffer> variables) throws InvalidRequestException - { - validate(variables); - - CFMetaData newCFMD; - try - { - AbstractType<?> comparator = cfProps.getComparator(); - - newCFMD = new CFMetaData(keyspace, - name, - ColumnFamilyType.Standard, - new SimpleDenseCellNameType(comparator)); - - if (CFMetaData.DEFAULT_COMPRESSOR != null && cfProps.compressionParameters.isEmpty()) - cfProps.compressionParameters.put(CompressionParameters.SSTABLE_COMPRESSION, CFMetaData.DEFAULT_COMPRESSOR); - int maxCompactionThreshold = getPropertyInt(CFPropDefs.KW_MAXCOMPACTIONTHRESHOLD, CFMetaData.DEFAULT_MAX_COMPACTION_THRESHOLD); - int minCompactionThreshold = getPropertyInt(CFPropDefs.KW_MINCOMPACTIONTHRESHOLD, CFMetaData.DEFAULT_MIN_COMPACTION_THRESHOLD); - if (minCompactionThreshold <= 0 || maxCompactionThreshold <= 0) - throw new ConfigurationException("Disabling compaction by setting compaction thresholds to 0 has been deprecated, set the compaction option 'enabled' to false instead."); - - newCFMD.addAllColumnDefinitions(getColumns(newCFMD)) - .comment(cfProps.getProperty(CFPropDefs.KW_COMMENT)) - .readRepairChance(getPropertyDouble(CFPropDefs.KW_READREPAIRCHANCE, CFMetaData.DEFAULT_READ_REPAIR_CHANCE)) - .dcLocalReadRepairChance(getPropertyDouble(CFPropDefs.KW_DCLOCALREADREPAIRCHANCE, CFMetaData.DEFAULT_DCLOCAL_READ_REPAIR_CHANCE)) - .gcGraceSeconds(getPropertyInt(CFPropDefs.KW_GCGRACESECONDS, CFMetaData.DEFAULT_GC_GRACE_SECONDS)) - .defaultValidator(cfProps.getValidator()) - .minCompactionThreshold(minCompactionThreshold) - .maxCompactionThreshold(maxCompactionThreshold) - .keyValidator(TypeParser.parse(CFPropDefs.comparators.get(getKeyType()))) - .compactionStrategyClass(cfProps.compactionStrategyClass) - .compactionStrategyOptions(cfProps.compactionStrategyOptions) - .compressionParameters(CompressionParameters.create(cfProps.compressionParameters)) - .caching(CFMetaData.Caching.fromString(getPropertyString(CFPropDefs.KW_CACHING, CFMetaData.DEFAULT_CACHING_STRATEGY.toString()))) - .rowsPerPartitionToCache(CFMetaData.RowsPerPartitionToCache.fromString(cfProps.getPropertyString(CFPropDefs.KW_ROWS_PER_PARTITION_TO_CACHE, CFMetaData.DEFAULT_ROWS_PER_PARTITION_TO_CACHE.toString()))) - .speculativeRetry(CFMetaData.SpeculativeRetry.fromString(getPropertyString(CFPropDefs.KW_SPECULATIVE_RETRY, CFMetaData.DEFAULT_SPECULATIVE_RETRY.toString()))) - .bloomFilterFpChance(getPropertyDouble(CFPropDefs.KW_BF_FP_CHANCE, null)) - .memtableFlushPeriod(getPropertyInt(CFPropDefs.KW_MEMTABLE_FLUSH_PERIOD, 0)) - .defaultTimeToLive(getPropertyInt(CFPropDefs.KW_DEFAULT_TIME_TO_LIVE, CFMetaData.DEFAULT_DEFAULT_TIME_TO_LIVE)) - .populateIoCacheOnFlush(getPropertyBoolean(CFPropDefs.KW_POPULATE_IO_CACHE_ON_FLUSH, CFMetaData.DEFAULT_POPULATE_IO_CACHE_ON_FLUSH)); - - // CQL2 can have null keyAliases - if (keyAlias != null) - newCFMD.addColumnDefinition(ColumnDefinition.partitionKeyDef(newCFMD, keyAlias, newCFMD.getKeyValidator(), null)); - } - catch (ConfigurationException e) - { - throw new InvalidRequestException(e.toString()); - } - catch (SyntaxException e) - { - throw new InvalidRequestException(e.toString()); - } - return newCFMD; - } - - private String getPropertyString(String key, String defaultValue) - { - return cfProps.getPropertyString(key, defaultValue); - } - - private Boolean getPropertyBoolean(String key, Boolean defaultValue) - { - return cfProps.getPropertyBoolean(key, defaultValue); - } - - private Double getPropertyDouble(String key, Double defaultValue) throws InvalidRequestException - { - return cfProps.getPropertyDouble(key, defaultValue); - } - - private Integer getPropertyInt(String key, Integer defaultValue) throws InvalidRequestException - { - return cfProps.getPropertyInt(key, defaultValue); - } - - private Set<String> getPropertySet(String key, Set<String> defaultValue) - { - return cfProps.getPropertySet(key, defaultValue); - } - - public Map<Term, String> getColumns() - { - return columns; - } - -} - http://git-wip-us.apache.org/repos/asf/cassandra/blob/26217071/src/java/org/apache/cassandra/cql/CreateIndexStatement.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql/CreateIndexStatement.java b/src/java/org/apache/cassandra/cql/CreateIndexStatement.java deleted file mode 100644 index 54b5eef..0000000 --- a/src/java/org/apache/cassandra/cql/CreateIndexStatement.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.cassandra.cql; - -/** A <code>CREATE INDEX</code> statement parsed from a CQL query. */ -public class CreateIndexStatement -{ - private final String columnFamily; - private final String indexName; - private final Term columnName; - - public CreateIndexStatement(String indexName, String columnFamily, Term columnName) - { - this.indexName = indexName; - this.columnFamily = columnFamily; - this.columnName = columnName; - } - - /** Column family namespace. */ - public String getColumnFamily() - { - return columnFamily; - } - - /** Column name to index. */ - public Term getColumnName() - { - return columnName; - } - - /** Index name (or null). */ - public String getIndexName() - { - return indexName; - } -} http://git-wip-us.apache.org/repos/asf/cassandra/blob/26217071/src/java/org/apache/cassandra/cql/CreateKeyspaceStatement.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql/CreateKeyspaceStatement.java b/src/java/org/apache/cassandra/cql/CreateKeyspaceStatement.java deleted file mode 100644 index 8c2aa1b..0000000 --- a/src/java/org/apache/cassandra/cql/CreateKeyspaceStatement.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.cassandra.cql; - -import java.util.HashMap; -import java.util.Map; - -import org.apache.cassandra.exceptions.InvalidRequestException; - -/** A <code>CREATE KEYSPACE</code> statement parsed from a CQL query. */ -public class CreateKeyspaceStatement -{ - private final String name; - private final Map<String, String> attrs; - private String strategyClass; - private final Map<String, String> strategyOptions = new HashMap<String, String>(); - - /** - * Creates a new <code>CreateKeyspaceStatement</code> instance for a given - * keyspace name and keyword arguments. - * - * @param name the name of the keyspace to create - * @param attrs map of the raw keyword arguments that followed the <code>WITH</code> keyword. - */ - public CreateKeyspaceStatement(String name, Map<String, String> attrs) - { - this.name = name; - this.attrs = attrs; - } - - /** - * The <code>CqlParser</code> only goes as far as extracting the keyword arguments - * from these statements, so this method is responsible for processing and - * validating, and must be called prior to access. - * - * @throws InvalidRequestException if arguments are missing or unacceptable - */ - public void validate() throws InvalidRequestException - { - // required - if (!attrs.containsKey("strategy_class")) - throw new InvalidRequestException("missing required argument \"strategy_class\""); - strategyClass = attrs.get("strategy_class"); - - // optional - for (String key : attrs.keySet()) - if ((key.contains(":")) && (key.startsWith("strategy_options"))) - strategyOptions.put(key.split(":")[1], attrs.get(key)); - } - - public String getName() - { - return name; - } - - public String getStrategyClass() - { - return strategyClass; - } - - public Map<String, String> getStrategyOptions() - { - return strategyOptions; - } -} http://git-wip-us.apache.org/repos/asf/cassandra/blob/26217071/src/java/org/apache/cassandra/cql/DeleteStatement.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql/DeleteStatement.java b/src/java/org/apache/cassandra/cql/DeleteStatement.java deleted file mode 100644 index 71942e4..0000000 --- a/src/java/org/apache/cassandra/cql/DeleteStatement.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.cassandra.cql; - -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.List; - -import org.apache.cassandra.auth.Permission; -import org.apache.cassandra.config.CFMetaData; -import org.apache.cassandra.config.Schema; -import org.apache.cassandra.db.Mutation; -import org.apache.cassandra.db.composites.CellName; -import org.apache.cassandra.db.IMutation; -import org.apache.cassandra.db.marshal.AbstractType; -import org.apache.cassandra.exceptions.InvalidRequestException; -import org.apache.cassandra.exceptions.UnauthorizedException; -import org.apache.cassandra.thrift.ThriftClientState; - -import static org.apache.cassandra.thrift.ThriftValidation.validateColumnFamily; -import static org.apache.cassandra.cql.QueryProcessor.validateColumnName; - -/** - * A <code>DELETE</code> parsed from a CQL query statement. - * - */ -public class DeleteStatement extends AbstractModification -{ - private List<Term> columns; - private List<Term> keys; - - public DeleteStatement(List<Term> columns, String keyspace, String columnFamily, String keyName, List<Term> keys, Attributes attrs) - { - super(keyspace, columnFamily, keyName, attrs); - - this.columns = columns; - this.keys = keys; - } - - public List<Term> getColumns() - { - return columns; - } - - public List<Term> getKeys() - { - return keys; - } - - public List<IMutation> prepareRowMutations(String keyspace, ThriftClientState clientState, List<ByteBuffer> variables) - throws InvalidRequestException, UnauthorizedException - { - return prepareRowMutations(keyspace, clientState, null, variables); - } - - public List<IMutation> prepareRowMutations(String keyspace, ThriftClientState clientState, Long timestamp, List<ByteBuffer> variables) - throws InvalidRequestException, UnauthorizedException - { - CFMetaData metadata = validateColumnFamily(keyspace, columnFamily); - - clientState.hasColumnFamilyAccess(keyspace, columnFamily, Permission.MODIFY); - AbstractType<?> keyType = Schema.instance.getCFMetaData(keyspace, columnFamily).getKeyValidator(); - - List<IMutation> mutations = new ArrayList<IMutation>(keys.size()); - - for (Term key : keys) - mutations.add(mutationForKey(key.getByteBuffer(keyType, variables), keyspace, timestamp, clientState, variables, metadata)); - - return mutations; - } - - public Mutation mutationForKey(ByteBuffer key, String keyspace, Long timestamp, ThriftClientState clientState, List<ByteBuffer> variables, CFMetaData metadata) - throws InvalidRequestException - { - Mutation mutation = new Mutation(keyspace, key); - - QueryProcessor.validateKeyAlias(metadata, keyName); - - if (columns.size() < 1) - { - // No columns, delete the partition - mutation.delete(columnFamily, (timestamp == null) ? getTimestamp(clientState) : timestamp); - } - else - { - // Delete specific columns - AbstractType<?> at = metadata.comparator.asAbstractType(); - for (Term column : columns) - { - CellName columnName = metadata.comparator.cellFromByteBuffer(column.getByteBuffer(at, variables)); - validateColumnName(columnName); - mutation.delete(columnFamily, columnName, (timestamp == null) ? getTimestamp(clientState) : timestamp); - } - } - - return mutation; - } - - public String toString() - { - return String.format("DeleteStatement(columns=%s, keyspace=%s, columnFamily=%s, consistency=%s keys=%s)", - columns, - keyspace, - columnFamily, - cLevel, - keys); - } -} http://git-wip-us.apache.org/repos/asf/cassandra/blob/26217071/src/java/org/apache/cassandra/cql/DropIndexStatement.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql/DropIndexStatement.java b/src/java/org/apache/cassandra/cql/DropIndexStatement.java deleted file mode 100644 index bc9bbbc..0000000 --- a/src/java/org/apache/cassandra/cql/DropIndexStatement.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.cassandra.cql; - -import org.apache.cassandra.config.*; -import org.apache.cassandra.exceptions.InvalidRequestException; - -public class DropIndexStatement -{ - public final String indexName; - private String keyspace; - - public DropIndexStatement(String indexName) - { - this.indexName = indexName; - } - - public void setKeyspace(String keyspace) - { - this.keyspace = keyspace; - } - - public String getColumnFamily() throws InvalidRequestException - { - return findIndexedCF().cfName; - } - - public CFMetaData generateCFMetadataUpdate() throws InvalidRequestException - { - return updateCFMetadata(findIndexedCF()); - } - - private CFMetaData updateCFMetadata(CFMetaData cfm) - { - ColumnDefinition column = findIndexedColumn(cfm); - assert column != null; - CFMetaData cloned = cfm.clone(); - ColumnDefinition toChange = cloned.getColumnDefinition(column.name); - assert toChange.getIndexName() != null && toChange.getIndexName().equals(indexName); - toChange.setIndexName(null); - toChange.setIndexType(null, null); - return cloned; - } - - private CFMetaData findIndexedCF() throws InvalidRequestException - { - KSMetaData ksm = Schema.instance.getKSMetaData(keyspace); - for (CFMetaData cfm : ksm.cfMetaData().values()) - { - if (findIndexedColumn(cfm) != null) - return cfm; - } - throw new InvalidRequestException("Index '" + indexName + "' could not be found in any of the column families of keyspace '" + keyspace + "'"); - } - - private ColumnDefinition findIndexedColumn(CFMetaData cfm) - { - for (ColumnDefinition column : cfm.regularColumns()) - { - if (column.getIndexType() != null && column.getIndexName() != null && column.getIndexName().equals(indexName)) - return column; - } - return null; - } -} http://git-wip-us.apache.org/repos/asf/cassandra/blob/26217071/src/java/org/apache/cassandra/cql/Operation.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql/Operation.java b/src/java/org/apache/cassandra/cql/Operation.java deleted file mode 100644 index 0f06433..0000000 --- a/src/java/org/apache/cassandra/cql/Operation.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.cassandra.cql; - -public class Operation -{ - public static enum OperationType - { PLUS, MINUS } - - public final OperationType type; - public final Term a, b; - - // unary operation - public Operation(Term a) - { - this.a = a; - type = null; - b = null; - } - - // binary operation - public Operation(Term a, OperationType type, Term b) - { - this.a = a; - this.type = type; - this.b = b; - } - - public boolean isUnary() - { - return type == null && b == null; - } - - public String toString() - { - return (isUnary()) - ? String.format("UnaryOperation(%s)", a) - : String.format("BinaryOperation(%s, %s, %s)", a, type, b); - } -}