diff --git a/client-java/controller/pom.xml b/client-java/controller/pom.xml index 27fa3c85a6..c300ee5f4f 100644 --- a/client-java/controller/pom.xml +++ b/client-java/controller/pom.xml @@ -81,10 +81,10 @@ javax.ws.rs-api 2.1.1 - - - - + + + + com.ea.agentloader @@ -122,6 +122,10 @@ com.github.jsqlparser jsqlparser + + org.antlr + antlr4-runtime + org.junit.jupiter junit-jupiter-engine @@ -346,13 +350,23 @@ net.sf.jsqlparser shaded.net.sf.jsqlparser + + org.antlr + shaded.org.antlr + + + + org.antlr + antlr4-maven-plugin + + - + \ No newline at end of file diff --git a/client-java/controller/src/main/antlr4/org/evomaster/client/java/controller/cassandra/parser/CqlLexer.g4 b/client-java/controller/src/main/antlr4/org/evomaster/client/java/controller/cassandra/parser/CqlLexer.g4 new file mode 100644 index 0000000000..04134206af --- /dev/null +++ b/client-java/controller/src/main/antlr4/org/evomaster/client/java/controller/cassandra/parser/CqlLexer.g4 @@ -0,0 +1,260 @@ +// $antlr-format alignTrailingComments true, columnLimit 150, maxEmptyLinesToKeep 1, reflowComments false, useTab false +// $antlr-format allowShortRulesOnASingleLine true, allowShortBlocksOnASingleLine true, minEmptyLines 0, alignSemicolons ownLine +// $antlr-format alignColons trailing, singleLineOverrulesHangingColon true, alignLexerCommands true, alignLabels true, alignTrailers true + +lexer grammar CqlLexer; + +options { + caseInsensitive = true; +} + +// Operators and Punctuators + +LR_BRACKET : '('; +RR_BRACKET : ')'; +LC_BRACKET : '{'; +RC_BRACKET : '}'; +LS_BRACKET : '['; +RS_BRACKET : ']'; +COMMA : ','; +SEMI : ';'; +COLON : ':'; +DOT : '.'; +STAR : '*'; +DIVIDE : '/'; +MODULE : '%'; +PLUS : '+'; +MINUSMINUS : '--'; +MINUS : '-'; +DQUOTE : '"'; +SQUOTE : '\''; +OPERATOR_EQ : '='; +OPERATOR_LT : '<'; +OPERATOR_GT : '>'; +OPERATOR_LTE : '<='; +OPERATOR_GTE : '>='; + +// Keywords + +K_ADD : 'ADD'; +K_AGGREGATE : 'AGGREGATE'; +K_ALL : 'ALL'; +K_ALLOW : 'ALLOW'; +K_ALTER : 'ALTER'; +K_AND : 'AND'; +K_ANY : 'ANY'; +K_APPLY : 'APPLY'; +K_AS : 'AS'; +K_ASC : 'ASC'; +K_AUTHORIZE : 'AUTHORIZE'; +K_BATCH : 'BATCH'; +K_BEGIN : 'BEGIN'; +K_BY : 'BY'; +K_CALLED : 'CALLED'; +K_CLUSTERING : 'CLUSTERING'; +K_COLUMNFAMILY : 'COLUMNFAMILY'; +K_COMPACT : 'COMPACT'; +K_CONSISTENCY : 'CONSISTENCY'; +K_CONTAINS : 'CONTAINS'; +K_CREATE : 'CREATE'; +K_CUSTOM : 'CUSTOM'; +K_DEFAULT : 'DEFAULT'; +K_DELETE : 'DELETE'; +K_DESC : 'DESC'; +K_DESCRIBE : 'DESCRIBE'; +K_DISTINCT : 'DISTINCT'; +K_DROP : 'DROP'; +K_DURABLE_WRITES : 'DURABLE_WRITES'; +K_EACH_QUORUM : 'EACH_QUORUM'; +K_ENTRIES : 'ENTRIES'; +K_EXECUTE : 'EXECUTE'; +K_EXISTS : 'EXISTS'; +K_FALSE : [Ff][Aa][Ll][Ss][Ee]; +K_FILTERING : 'FILTERING'; +K_FINALFUNC : 'FINALFUNC'; +K_FROM : 'FROM'; +K_FULL : 'FULL'; +K_FUNCTION : 'FUNCTION'; +K_FUNCTIONS : 'FUNCTIONS'; +K_GRANT : 'GRANT'; +K_IF : 'IF'; +K_IN : 'IN'; +K_INDEX : 'INDEX'; +K_INFINITY : 'INFINITY'; +K_INITCOND : 'INITCOND'; +K_INPUT : 'INPUT'; +K_INSERT : 'INSERT'; +K_INTO : 'INTO'; +K_IS : 'IS'; +K_JSON : 'JSON'; +K_KEY : 'KEY'; +K_KEYS : 'KEYS'; +K_KEYSPACE : 'KEYSPACE'; +K_KEYSPACES : 'KEYSPACES'; +K_LANGUAGE : 'LANGUAGE'; +K_LEVEL : 'LEVEL'; +K_LIMIT : 'LIMIT'; +K_LOCAL_ONE : 'LOCAL_ONE'; +K_LOCAL_QUORUM : 'LOCAL_QUORUM'; +K_LOGGED : 'LOGGED'; +K_LOGIN : 'LOGIN'; +K_MASKED : 'MASKED'; +K_MATERIALIZED : 'MATERIALIZED'; +K_MODIFY : 'MODIFY'; +K_NAN : 'NAN'; +K_NORECURSIVE : 'NORECURSIVE'; +K_NOSUPERUSER : 'NOSUPERUSER'; +K_NOT : 'NOT'; +K_NULL : 'NULL'; +K_OF : 'OF'; +K_ON : 'ON'; +K_ONE : 'ONE'; +K_OPTIONS : 'OPTIONS'; +K_OR : 'OR'; +K_ORDER : 'ORDER'; +K_PARTITION : 'PARTITION'; +K_PASSWORD : 'PASSWORD'; +K_PER : 'PER'; +K_PERMISSION : 'PERMISSION'; +K_PERMISSIONS : 'PERMISSIONS'; +K_PRIMARY : 'PRIMARY'; +K_QUORUM : 'QUORUM'; +K_RENAME : 'RENAME'; +K_REPLACE : 'REPLACE'; +K_REPLICATION : 'REPLICATION'; +K_RETURNS : 'RETURNS'; +K_REVOKE : 'REVOKE'; +K_ROLE : 'ROLE'; +K_ROLES : 'ROLES'; +K_SCHEMA : 'SCHEMA'; +K_SELECT : 'SELECT'; +K_SET : 'SET'; +K_SFUNC : 'SFUNC'; +K_STATIC : 'STATIC'; +K_STORAGE : 'STORAGE'; +K_STYPE : 'STYPE'; +K_SUPERUSER : 'SUPERUSER'; +K_TABLE : 'TABLE'; +K_THREE : 'THREE'; +K_TIMESTAMP : 'TIMESTAMP'; +K_TO : 'TO'; +K_TOKEN : 'TOKEN'; +K_TRIGGER : 'TRIGGER'; +K_TRUE : [Tt][Rr][Uu][Ee]; +K_TRUNCATE : 'TRUNCATE'; +K_TTL : 'TTL'; +K_TWO : 'TWO'; +K_TYPE : 'TYPE'; +K_UNLOGGED : 'UNLOGGED'; +K_UPDATE : 'UPDATE'; +K_USE : 'USE'; +K_USER : 'USER'; +K_USING : 'USING'; +K_UUID : 'UUID'; +K_VALUES : 'VALUES'; +K_VECTOR : 'VECTOR'; +K_VIEW : 'VIEW'; +K_WHERE : 'WHERE'; +K_WITH : 'WITH'; +K_WRITETIME : 'WRITETIME'; +K_ASCII : 'ASCII'; +K_BIGINT : 'BIGINT'; +K_BLOB : 'BLOB'; +K_BOOLEAN : 'BOOLEAN'; +K_COUNTER : 'COUNTER'; +K_DATE : 'DATE'; +K_DECIMAL : 'DECIMAL'; +K_DOUBLE : 'DOUBLE'; +K_FLOAT : 'FLOAT'; +K_FROZEN : 'FROZEN'; +K_INET : 'INET'; +K_INT : 'INT'; +K_LIST : 'LIST'; +K_MAP : 'MAP'; +K_SMALLINT : 'SMALLINT'; +K_TEXT : 'TEXT'; +K_TIMEUUID : 'TIMEUUID'; +K_TIME : 'TIME'; +K_TINYINT : 'TINYINT'; +K_TUPLE : 'TUPLE'; +K_VARCHAR : 'VARCHAR'; +K_VARINT : 'VARINT'; + +// Literals + +CODE_BLOCK: '$$' (~ '$' | '$' ~'$')* '$$'; + +STRING_LITERAL: '\'' ('\\' . | '\'\'' | ~('\'' | '\\'))* '\''; + +DECIMAL_LITERAL: DEC_DIGIT+; + +FLOAT_LITERAL: MINUS? [0-9]+ (DOT [0-9]+)?; + +HEXADECIMAL_LITERAL: 'X' '\'' (HEX_DIGIT HEX_DIGIT)+ '\'' | '0X' HEX_DIGIT+; + +REAL_LITERAL: DEC_DIGIT+ '.'? EXPONENT_NUM_PART | DEC_DIGIT* '.' DEC_DIGIT+ EXPONENT_NUM_PART?; + +// Duration literal — must appear before OBJECT_NAME so that ISO-format tokens like +// PT89H8M53S or P1Y2M3D are not consumed as OBJECT_NAME first. +// Three accepted formats (all case-insensitive via explicit char classes): +// 1. Standard quantity-unit: 89h4m48s 1y2mo3d -2mo (units: y mo w d h ms m us ns s) +// 2. ISO 8601 standard: P1Y2M3DT4H5M6S PT89H8M53S +// 3. ISO 8601 alternative: P0000-00-00T89:09:09 +DURATION_LITERAL + : MINUS? DEC_DIGIT+ DURATION_UNIT (DEC_DIGIT+ DURATION_UNIT)* + | [pP] DURATION_ISO_BODY + ; + +OBJECT_NAME: [A-Za-z] [A-Za-z0-9_$]* | '"' ~'"'+ '"'; + +UUID: + HEX_4DIGIT HEX_4DIGIT '-' HEX_4DIGIT '-' HEX_4DIGIT '-' HEX_4DIGIT '-' HEX_4DIGIT HEX_4DIGIT HEX_4DIGIT +; + +// Hidden + +SPACE : [ \t\r\n]+ -> channel (HIDDEN); +SPEC_MYSQL_COMMENT : '/*!' .+? '*/' -> channel (HIDDEN); +COMMENT_INPUT : '/*' .*? '*/' -> channel (HIDDEN); +LINE_COMMENT: + (('-- ' | '#' | '//') ~ [\r\n]* ('\r'? '\n' | EOF) | '--' ('\r'? '\n' | EOF)) -> channel (HIDDEN) +; + +// Fragments + +fragment HEX_4DIGIT: [0-9A-Fa-f] [0-9A-Fa-f] [0-9A-Fa-f] [0-9A-Fa-f]; + +fragment HEX_DIGIT: [0-9A-Fa-f]; + +fragment DEC_DIGIT: [0-9]; + +fragment EXPONENT_NUM_PART: 'E' '-'? DEC_DIGIT+; + +// Duration unit suffixes — ordered longest-first within each ambiguous group: +// 'mo' before 'm', 'ms' before 'm', 'us' before 's', 'ns' before 's' +fragment DURATION_UNIT + : [yY] + | [mM][oO] + | [wW] + | [dD] + | [hH] + | [mM][sS] + | [mM] + | [uU][sS] + | [nN][sS] + | [sS] + ; + +// ISO 8601 duration body (the part after the leading P). +// Each alternative requires at least one component so that bare 'P' or 'PT' is not matched. +// Date-M (months) is unambiguous from time-M (minutes) because time components follow the T separator. +fragment DURATION_ISO_BODY + : DEC_DIGIT+ [yY] (DEC_DIGIT+ [mM])? (DEC_DIGIT+ [wW])? (DEC_DIGIT+ [dD])? ([tT] (DEC_DIGIT+ [hH])? (DEC_DIGIT+ [mM])? (DEC_DIGIT+ [sS])?)? + | DEC_DIGIT+ [mM] (DEC_DIGIT+ [wW])? (DEC_DIGIT+ [dD])? ([tT] (DEC_DIGIT+ [hH])? (DEC_DIGIT+ [mM])? (DEC_DIGIT+ [sS])?)? + | DEC_DIGIT+ [wW] (DEC_DIGIT+ [dD])? ([tT] (DEC_DIGIT+ [hH])? (DEC_DIGIT+ [mM])? (DEC_DIGIT+ [sS])?)? + | DEC_DIGIT+ [dD] ([tT] (DEC_DIGIT+ [hH])? (DEC_DIGIT+ [mM])? (DEC_DIGIT+ [sS])?)? + | [tT] DEC_DIGIT+ [hH] (DEC_DIGIT+ [mM])? (DEC_DIGIT+ [sS])? + | [tT] DEC_DIGIT+ [mM] (DEC_DIGIT+ [sS])? + | [tT] DEC_DIGIT+ [sS] + | DEC_DIGIT DEC_DIGIT DEC_DIGIT DEC_DIGIT '-' DEC_DIGIT DEC_DIGIT '-' DEC_DIGIT DEC_DIGIT [tT] DEC_DIGIT DEC_DIGIT ':' DEC_DIGIT DEC_DIGIT ':' DEC_DIGIT DEC_DIGIT + ; \ No newline at end of file diff --git a/client-java/controller/src/main/antlr4/org/evomaster/client/java/controller/cassandra/parser/CqlParser.g4 b/client-java/controller/src/main/antlr4/org/evomaster/client/java/controller/cassandra/parser/CqlParser.g4 new file mode 100644 index 0000000000..94e1bbba3b --- /dev/null +++ b/client-java/controller/src/main/antlr4/org/evomaster/client/java/controller/cassandra/parser/CqlParser.g4 @@ -0,0 +1,1368 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2014 by Domagoj Kovačević + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + * associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT + * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Project : cql-parser; an ANTLR4 grammar for Apache Cassandra CQL github.com/kdcro101cql-parser + */ + +// $antlr-format alignTrailingComments true, columnLimit 150, minEmptyLines 1, maxEmptyLinesToKeep 1, reflowComments false, useTab false +// $antlr-format allowShortRulesOnASingleLine false, allowShortBlocksOnASingleLine true, alignSemicolons hanging, alignColons hanging + +parser grammar CqlParser; + +options + { + tokenVocab = CqlLexer; +} + +root + : cqls? MINUSMINUS? EOF + ; + +cqls + : (cql MINUSMINUS? statementSeparator | empty_)* ( + cql (MINUSMINUS? statementSeparator)? + | empty_ + ) + ; + +statementSeparator + : SEMI + ; + +empty_ + : statementSeparator + ; + +cql + : alterKeyspace + | alterMaterializedView + | alterRole + | alterTable + | alterType + | alterUser + | applyBatch + | createAggregate + | createFunction + | createIndex + | createKeyspace + | createMaterializedView + | createRole + | createTable + | createTrigger + | createType + | createUser + | delete_ + | dropAggregate + | dropFunction + | dropIndex + | dropKeyspace + | dropMaterializedView + | dropRole + | dropTable + | dropTrigger + | dropType + | dropUser + | grant + | insert + | listPermissions + | listRoles + | revoke + | select_ + | truncate + | update + | use_ + ; + +revoke + : kwRevoke priviledge kwOn resource kwFrom role + ; + +listRoles + : kwList kwRoles (kwOf role)? kwNorecursive? + ; + +listPermissions + : kwList priviledge (kwOn resource)? (kwOf role)? + ; + +grant + : kwGrant priviledge kwOn resource kwTo role + ; + +priviledge + : (kwAll | kwAllPermissions) + | kwAlter + | kwAuthorize + | kwDescribe + | kwExecute + | kwCreate + | kwDrop + | kwModify + | kwSelect + ; + +resource + : kwAll kwFunctions + | kwAll kwFunctions kwIn kwKeyspace keyspace + | kwFunction (keyspace DOT)? function_ + | kwAll kwKeyspaces + | kwKeyspace keyspace + | (kwTable)? (keyspace DOT)? table + | kwAll kwRoles + | kwRole role + ; + +createUser + : kwCreate kwUser ifNotExist? user kwWith kwPassword stringLiteral ( + kwSuperuser + | kwNosuperuser + )? + ; + +createRole + : kwCreate kwRole ifNotExist? role roleWith? + ; + +createType + : kwCreate kwType ifNotExist? (keyspace DOT)? type_ syntaxBracketLr typeMemberColumnList syntaxBracketRr + ; + +typeMemberColumnList + : column dataType (syntaxComma column dataType)* + ; + +createTrigger + : kwCreate kwTrigger ifNotExist? (keyspace DOT)? trigger kwUsing triggerClass + ; + +createMaterializedView + : kwCreate kwMaterialized kwView ifNotExist? (keyspace DOT)? materializedView kwAs kwSelect columnList kwFrom ( + keyspace DOT + )? table materializedViewWhere kwPrimary kwKey syntaxBracketLr columnList syntaxBracketRr ( + kwWith materializedViewOptions + )? + ; + +materializedViewWhere + : kwWhere columnNotNullList (kwAnd relationElements)? + ; + +columnNotNullList + : columnNotNull (kwAnd columnNotNull)* + ; + +columnNotNull + : column kwIs kwNot kwNull + ; + +materializedViewOptions + : tableOptions + | tableOptions kwAnd clusteringOrder + | clusteringOrder + ; + +// CREATE MATERIALIZED VIEW [IF NOT EXISTS] [keyspace_name.] view_name +// AS SELECT column_list +// FROM [keyspace_name.] base_table_name +// WHERE column_name IS NOT NULL [AND column_name IS NOT NULL ...] +// [AND relation...] +// PRIMARY KEY ( column_list ) +// [WITH [table_properties] +// [AND CLUSTERING ORDER BY (cluster_column_name order_option )]] +createKeyspace + : kwCreate kwKeyspace ifNotExist? keyspace kwWith kwReplication OPERATOR_EQ syntaxBracketLc replicationList syntaxBracketRc ( + kwAnd durableWrites + )? + ; + +createFunction + : kwCreate orReplace? kwFunction ifNotExist? (keyspace DOT)? function_ syntaxBracketLr paramList? syntaxBracketRr returnMode kwReturns dataType + kwLanguage language kwAs codeBlock + ; + +codeBlock + : CODE_BLOCK + | STRING_LITERAL + ; + +paramList + : param (syntaxComma param)* + ; + +returnMode + : (kwCalled | kwReturns kwNull) kwOn kwNull kwInput + ; + +createAggregate + : kwCreate orReplace? kwAggregate ifNotExist? (keyspace DOT)? aggregate syntaxBracketLr dataType syntaxBracketRr kwSfunc function_ kwStype + dataType kwFinalfunc function_ kwInitcond initCondDefinition + ; + +// paramList +// : +initCondDefinition + : constant + | initCondList + | initCondListNested + | initCondHash + ; + +initCondHash + : syntaxBracketLc initCondHashItem (syntaxComma initCondHashItem)* syntaxBracketRc + ; + +initCondHashItem + : hashKey COLON initCondDefinition + ; + +initCondListNested + : syntaxBracketLr initCondList (syntaxComma constant | initCondList)* syntaxBracketRr + ; + +initCondList + : syntaxBracketLr constant (syntaxComma constant)* syntaxBracketRr + ; + +orReplace + : kwOr kwReplace + ; + +alterUser + : kwAlter kwUser user kwWith userPassword userSuperUser? + ; + +userPassword + : kwPassword stringLiteral + ; + +userSuperUser + : kwSuperuser + | kwNosuperuser + ; + +alterType + : kwAlter kwType (keyspace DOT)? type_ alterTypeOperation + ; + +alterTypeOperation + : alterTypeAlterType + | alterTypeAdd + | alterTypeRename + ; + +alterTypeRename + : kwRename alterTypeRenameList + ; + +alterTypeRenameList + : alterTypeRenameItem (kwAnd alterTypeRenameItem)* + ; + +alterTypeRenameItem + : column kwTo column + ; + +alterTypeAdd + : kwAdd column dataType (syntaxComma column dataType)* + ; + +alterTypeAlterType + : kwAlter column kwType dataType + ; + +alterTable + : kwAlter kwTable ifExist? (keyspace DOT)? table alterTableOperation + ; + +alterTableOperation + : alterTableAdd + | alterTableAlter + | alterTableDropColumns + | alterTableDropCompactStorage + | alterTableRename + | alterTableWith + ; + +alterTableWith + : kwWith tableOptions + ; + +alterTableRename + : kwRename ifExist? column kwTo column (K_AND column kwTo column)* + ; + +alterTableDropCompactStorage + : kwDrop kwCompact kwStorage + ; + +alterTableDropColumns + : kwDrop ifExist? alterTableDropColumnList + ; + +alterTableDropColumnList + : column (syntaxComma column)* + ; + +alterTableAdd + : kwAdd ifNotExist? alterTableColumnDefinition + ; + +alterTableColumnDefinition + : alterColumnDefinition (syntaxComma alterColumnDefinition)* + ; + +alterTableAlter + : kwAlter ifExist? column (column_mask | K_DROP K_MASKED) + ; + +alterColumnDefinition + : column dataType column_mask? + ; + +alterRole + : kwAlter kwRole role roleWith? + ; + +roleWith + : kwWith (roleWithOptions (kwAnd roleWithOptions)*) + ; + +roleWithOptions + : kwPassword OPERATOR_EQ stringLiteral + | kwLogin OPERATOR_EQ booleanLiteral + | kwSuperuser OPERATOR_EQ booleanLiteral + | kwOptions OPERATOR_EQ optionHash + ; + +alterMaterializedView + : kwAlter kwMaterialized kwView (keyspace DOT)? materializedView (kwWith tableOptions)? + ; + +dropUser + : kwDrop kwUser ifExist? user + ; + +dropType + : kwDrop kwType ifExist? (keyspace DOT)? type_ + ; + +dropMaterializedView + : kwDrop kwMaterialized kwView ifExist? (keyspace DOT)? materializedView + ; + +dropAggregate + : kwDrop kwAggregate ifExist? (keyspace DOT)? aggregate + ; + +dropFunction + : kwDrop kwFunction ifExist? (keyspace DOT)? function_ + ; + +dropTrigger + : kwDrop kwTrigger ifExist? trigger kwOn (keyspace DOT)? table + ; + +dropRole + : kwDrop kwRole ifExist? role + ; + +dropTable + : kwDrop kwTable ifExist? (keyspace DOT)? table + ; + +dropKeyspace + : kwDrop kwKeyspace ifExist? keyspace + ; + +dropIndex + : kwDrop kwIndex ifExist? (keyspace DOT)? indexName + ; + +createTable + : kwCreate kwTable ifNotExist? (keyspace DOT)? table syntaxBracketLr columnDefinitionList syntaxBracketRr withElement? + ; + +withElement + : kwWith tableOptions + ; + +tableOptions + : kwCompact kwStorage (kwAnd tableOptions)? + | clusteringOrder (kwAnd tableOptions)? + | tableOptionItem (kwAnd tableOptionItem)* + ; + +clusteringOrder + : kwClustering kwOrder kwBy syntaxBracketLr (column orderDirection?) (syntaxComma column orderDirection?)* syntaxBracketRr + ; + +tableOptionItem + : tableOptionName OPERATOR_EQ tableOptionValue + | tableOptionName OPERATOR_EQ optionHash + ; + +tableOptionName + : OBJECT_NAME + ; + +tableOptionValue + : stringLiteral + | floatLiteral + ; + +optionHash + : syntaxBracketLc optionHashItem (syntaxComma optionHashItem)* syntaxBracketRc + ; + +optionHashItem + : optionHashKey COLON optionHashValue + ; + +optionHashKey + : stringLiteral + ; + +optionHashValue + : stringLiteral + | floatLiteral + ; + +columnDefinitionList + : (columnDefinition) (syntaxComma columnDefinition)* (syntaxComma primaryKeyElement)? + ; + +// +columnDefinition + : column dataType K_STATIC? column_mask? primaryKeyColumn? + ; + +column_mask + : K_MASKED K_WITH (K_DEFAULT | function_name '(' functionArgs? ')' ) + ; + +function_name + : (keyspace '.')? function_ + ; + +// +primaryKeyColumn + : kwPrimary kwKey + ; + +primaryKeyElement + : kwPrimary kwKey syntaxBracketLr primaryKeyDefinition syntaxBracketRr + ; + +primaryKeyDefinition + : singlePrimaryKey + | compoundKey + | compositeKey + ; + +singlePrimaryKey + : column + ; + +compoundKey + : partitionKey (syntaxComma clusteringKeyList) + ; + +compositeKey + : syntaxBracketLr partitionKeyList syntaxBracketRr (syntaxComma clusteringKeyList) + ; + +partitionKeyList + : (partitionKey) (syntaxComma partitionKey)* + ; + +clusteringKeyList + : (clusteringKey) (syntaxComma clusteringKey)* + ; + +partitionKey + : column + ; + +clusteringKey + : column + ; + +applyBatch + : kwApply kwBatch + ; + +beginBatch + : kwBegin batchType? kwBatch usingTimestampSpec? + ; + +batchType + : kwLogged + | kwUnlogged + ; + +alterKeyspace + : kwAlter kwKeyspace keyspace kwWith kwReplication OPERATOR_EQ syntaxBracketLc replicationList syntaxBracketRc ( + kwAnd durableWrites + )? + ; + +replicationList + : (replicationListItem) (syntaxComma replicationListItem)* + ; + +replicationListItem + : STRING_LITERAL COLON STRING_LITERAL + | STRING_LITERAL COLON DECIMAL_LITERAL + ; + +durableWrites + : kwDurableWrites OPERATOR_EQ booleanLiteral + ; + +use_ + : kwUse keyspace + ; + +truncate + : kwTruncate (kwTable)? (keyspace DOT)? table + ; + +createIndex + : kwCreate kwIndex ifNotExist? indexName? kwOn (keyspace DOT)? table syntaxBracketLr indexColumnSpec syntaxBracketRr + ; + +indexName + : OBJECT_NAME + | stringLiteral + ; + +indexColumnSpec + : column + | indexKeysSpec + | indexEntriesSSpec + | indexFullSpec + ; + +indexKeysSpec + : kwKeys syntaxBracketLr OBJECT_NAME syntaxBracketRr + ; + +indexEntriesSSpec + : kwEntries syntaxBracketLr OBJECT_NAME syntaxBracketRr + ; + +indexFullSpec + : kwFull syntaxBracketLr OBJECT_NAME syntaxBracketRr + ; + +delete_ + : beginBatch? kwDelete deleteColumnList? fromSpec usingTimestampSpec? whereSpec ( + ifExist + | ifSpec + )? + ; + +deleteColumnList + : (deleteColumnItem) (syntaxComma deleteColumnItem)* + ; + +deleteColumnItem + : OBJECT_NAME + | OBJECT_NAME LS_BRACKET (stringLiteral | decimalLiteral) RS_BRACKET + ; + +update + : beginBatch? kwUpdate (keyspace DOT)? table usingTtlTimestamp? kwSet assignments whereSpec ( + ifExist + | ifSpec + )? + ; + +ifSpec + : kwIf ifConditionList + ; + +ifConditionList + : (ifCondition) (kwAnd ifCondition)* + ; + +ifCondition + : OBJECT_NAME OPERATOR_EQ constant + ; + +assignments + : (assignmentElement) (syntaxComma assignmentElement)* + ; + +assignmentElement + : OBJECT_NAME OPERATOR_EQ (constant | assignmentMap | assignmentSet | assignmentList) + | OBJECT_NAME OPERATOR_EQ OBJECT_NAME (PLUS | MINUS) decimalLiteral + | OBJECT_NAME OPERATOR_EQ OBJECT_NAME (PLUS | MINUS) assignmentSet + | OBJECT_NAME OPERATOR_EQ assignmentSet (PLUS | MINUS) OBJECT_NAME + | OBJECT_NAME OPERATOR_EQ OBJECT_NAME (PLUS | MINUS) assignmentMap + | OBJECT_NAME OPERATOR_EQ assignmentMap (PLUS | MINUS) OBJECT_NAME + | OBJECT_NAME OPERATOR_EQ OBJECT_NAME (PLUS | MINUS) assignmentList + | OBJECT_NAME OPERATOR_EQ assignmentList (PLUS | MINUS) OBJECT_NAME + | OBJECT_NAME syntaxBracketLs decimalLiteral syntaxBracketRs OPERATOR_EQ constant + ; + +assignmentSet + : syntaxBracketLc (constant (syntaxComma constant)*)? syntaxBracketRc + ; + +assignmentMap + : syntaxBracketLc (constant syntaxColon constant) (syntaxComma constant syntaxColon constant)* syntaxBracketRc + ; + +assignmentList + : syntaxBracketLs constant (syntaxComma constant)* syntaxBracketRs + ; + +assignmentTuple + : syntaxBracketLr (expression (syntaxComma expression)*) syntaxBracketRr + ; + +insert + : beginBatch? kwInsert kwInto (keyspace DOT)? table insertColumnSpec? insertValuesSpec ifNotExist? usingTtlTimestamp? + ; + +usingTtlTimestamp + : kwUsing ttl + | kwUsing ttl kwAnd timestamp + | kwUsing timestamp + | kwUsing timestamp kwAnd ttl + ; + +timestamp + : kwTimestamp decimalLiteral + ; + +ttl + : kwTtl decimalLiteral + ; + +usingTimestampSpec + : kwUsing timestamp + ; + +ifNotExist + : kwIf kwNot kwExists + ; + +ifExist + : kwIf kwExists + ; + +insertValuesSpec + : kwValues '(' expressionList ')' + | kwJson constant + ; + +insertColumnSpec + : '(' columnList ')' + ; + +columnList + : column (syntaxComma column)* + ; + +expressionList + : expression (syntaxComma expression)* + ; + +expression + : constant + | functionCall + | assignmentMap + | assignmentSet + | assignmentList + | assignmentTuple + ; + +select_ + : kwSelect distinctSpec? kwJson? selectElements fromSpec whereSpec? orderSpec? limitSpec? allowFilteringSpec? + ; + +allowFilteringSpec + : kwAllow kwFiltering + ; + +limitSpec + : kwLimit decimalLiteral + ; + +fromSpec + : kwFrom fromSpecElement + ; + +fromSpecElement + : OBJECT_NAME + | OBJECT_NAME '.' OBJECT_NAME + ; + +orderSpec + : kwOrder kwBy orderSpecElement + ; + +orderSpecElement + : OBJECT_NAME (kwAsc | kwDesc)? + ; + +whereSpec + : kwWhere relationElements + ; + +distinctSpec + : kwDistinct + ; + +selectElements + : (star = '*' | selectElement) (syntaxComma selectElement)* + ; + +selectElement + : OBJECT_NAME '.' '*' + | OBJECT_NAME (kwAs OBJECT_NAME)? + | functionCall (kwAs OBJECT_NAME)? + ; + +relationElements + : (relationElement) (kwAnd relationElement)* + ; + +relationElement + : OBJECT_NAME (OPERATOR_EQ | OPERATOR_LT | OPERATOR_GT | OPERATOR_LTE | OPERATOR_GTE) constant + | OBJECT_NAME '.' OBJECT_NAME ( + OPERATOR_EQ + | OPERATOR_LT + | OPERATOR_GT + | OPERATOR_LTE + | OPERATOR_GTE + ) constant + | functionCall (OPERATOR_EQ | OPERATOR_LT | OPERATOR_GT | OPERATOR_LTE | OPERATOR_GTE) constant + | functionCall (OPERATOR_EQ | OPERATOR_LT | OPERATOR_GT | OPERATOR_LTE | OPERATOR_GTE) functionCall + | OBJECT_NAME kwIn '(' functionArgs? ')' + | '(' OBJECT_NAME (syntaxComma OBJECT_NAME)* ')' kwIn '(' assignmentTuple ( + syntaxComma assignmentTuple + )* ')' + | '(' OBJECT_NAME (syntaxComma OBJECT_NAME)* ')' ( + OPERATOR_EQ + | OPERATOR_LT + | OPERATOR_GT + | OPERATOR_LTE + | OPERATOR_GTE + ) (assignmentTuple (syntaxComma assignmentTuple)*) + | relalationContainsKey + | relalationContains + ; + +relalationContains + : OBJECT_NAME kwContains constant + ; + +relalationContainsKey + : OBJECT_NAME (kwContains kwKey) constant + ; + +functionCall + : OBJECT_NAME '(' STAR ')' + | OBJECT_NAME '(' functionArgs? ')' + | K_UUID '(' ')' + ; + +functionArgs + : (constant | OBJECT_NAME | functionCall) (syntaxComma (constant | OBJECT_NAME | functionCall))* + ; + +constant + : UUID + | stringLiteral + | decimalLiteral + | floatLiteral + | hexadecimalLiteral + | booleanLiteral + | durationLiteral + | codeBlock + | kwNull + ; + +decimalLiteral + : DECIMAL_LITERAL + ; + +floatLiteral + : DECIMAL_LITERAL + | FLOAT_LITERAL + ; + +stringLiteral + : STRING_LITERAL + ; + +booleanLiteral + : K_TRUE + | K_FALSE + ; + +hexadecimalLiteral + : HEXADECIMAL_LITERAL + ; + +durationLiteral + : DURATION_LITERAL + ; + +keyspace + : OBJECT_NAME + | DQUOTE OBJECT_NAME DQUOTE + ; + +table + : OBJECT_NAME + | DQUOTE OBJECT_NAME DQUOTE + ; + +column + : OBJECT_NAME + | DQUOTE OBJECT_NAME DQUOTE + ; + +dataType + : dataTypeName dataTypeDefinition? + ; + +dataTypeName + : OBJECT_NAME + | K_TIMESTAMP + | K_SET + | K_ASCII + | K_BIGINT + | K_BLOB + | K_BOOLEAN + | K_COUNTER + | K_DATE + | K_DECIMAL + | K_DOUBLE + | K_FLOAT + | K_FROZEN + | K_INET + | K_INT + | K_LIST + | K_MAP + | K_SMALLINT + | K_TEXT + | K_TIME + | K_TIMEUUID + | K_TINYINT + | K_TUPLE + | K_VARCHAR + | K_VARINT + | K_TIMESTAMP + | K_UUID + | K_VECTOR + ; + +dataTypeDefinition + : syntaxBracketLa dataTypeName (syntaxComma dataTypeName)* syntaxBracketRa + ; + +orderDirection + : kwAsc + | kwDesc + ; + +role + : OBJECT_NAME + ; + +trigger + : OBJECT_NAME + ; + +triggerClass + : stringLiteral + ; + +materializedView + : OBJECT_NAME + ; + +type_ + : OBJECT_NAME + ; + +aggregate + : OBJECT_NAME + ; + +function_ + : OBJECT_NAME + ; + +language + : OBJECT_NAME + ; + +user + : OBJECT_NAME + ; + +password + : stringLiteral + ; + +hashKey + : OBJECT_NAME + ; + +param + : paramName dataType + ; + +paramName + : OBJECT_NAME + | K_INPUT + ; + +kwAdd + : K_ADD + ; + +kwAggregate + : K_AGGREGATE + ; + +kwAll + : K_ALL + ; + +kwAllPermissions + : K_ALL K_PERMISSIONS + ; + +kwAllow + : K_ALLOW + ; + +kwAlter + : K_ALTER + ; + +kwAnd + : K_AND + ; + +kwApply + : K_APPLY + ; + +kwAs + : K_AS + ; + +kwAsc + : K_ASC + ; + +kwAuthorize + : K_AUTHORIZE + ; + +kwBatch + : K_BATCH + ; + +kwBegin + : K_BEGIN + ; + +kwBy + : K_BY + ; + +kwCalled + : K_CALLED + ; + +kwClustering + : K_CLUSTERING + ; + +kwCompact + : K_COMPACT + ; + +kwContains + : K_CONTAINS + ; + +kwCreate + : K_CREATE + ; + +kwDelete + : K_DELETE + ; + +kwDesc + : K_DESC + ; + +kwDescribe + : K_DESCRIBE + ; + +kwDistinct + : K_DISTINCT + ; + +kwDrop + : K_DROP + ; + +kwDurableWrites + : K_DURABLE_WRITES + ; + +kwEntries + : K_ENTRIES + ; + +kwExecute + : K_EXECUTE + ; + +kwExists + : K_EXISTS + ; + +kwFiltering + : K_FILTERING + ; + +kwFinalfunc + : K_FINALFUNC + ; + +kwFrom + : K_FROM + ; + +kwFull + : K_FULL + ; + +kwFunction + : K_FUNCTION + ; + +kwFunctions + : K_FUNCTIONS + ; + +kwGrant + : K_GRANT + ; + +kwIf + : K_IF + ; + +kwIn + : K_IN + ; + +kwIndex + : K_INDEX + ; + +kwInitcond + : K_INITCOND + ; + +kwInput + : K_INPUT + ; + +kwInsert + : K_INSERT + ; + +kwInto + : K_INTO + ; + +kwIs + : K_IS + ; + +kwJson + : K_JSON + ; + +kwKey + : K_KEY + ; + +kwKeys + : K_KEYS + ; + +kwKeyspace + : K_KEYSPACE + ; + +kwKeyspaces + : K_KEYSPACES + ; + +kwLanguage + : K_LANGUAGE + ; + +kwLimit + : K_LIMIT + ; + +kwList + : K_LIST + ; + +kwLogged + : K_LOGGED + ; + +kwLogin + : K_LOGIN + ; + +kwMaterialized + : K_MATERIALIZED + ; + +kwModify + : K_MODIFY + ; + +kwNosuperuser + : K_NOSUPERUSER + ; + +kwNorecursive + : K_NORECURSIVE + ; + +kwNot + : K_NOT + ; + +kwNull + : K_NULL + ; + +kwOf + : K_OF + ; + +kwOn + : K_ON + ; + +kwOptions + : K_OPTIONS + ; + +kwOr + : K_OR + ; + +kwOrder + : K_ORDER + ; + +kwPassword + : K_PASSWORD + ; + +kwPrimary + : K_PRIMARY + ; + +kwRename + : K_RENAME + ; + +kwReplace + : K_REPLACE + ; + +kwReplication + : K_REPLICATION + ; + +kwReturns + : K_RETURNS + ; + +kwRole + : K_ROLE + ; + +kwRoles + : K_ROLES + ; + +kwSelect + : K_SELECT + ; + +kwSet + : K_SET + ; + +kwSfunc + : K_SFUNC + ; + +kwStorage + : K_STORAGE + ; + +kwStype + : K_STYPE + ; + +kwSuperuser + : K_SUPERUSER + ; + +kwTable + : K_TABLE + ; + +kwTimestamp + : K_TIMESTAMP + ; + +kwTo + : K_TO + ; + +kwTrigger + : K_TRIGGER + ; + +kwTruncate + : K_TRUNCATE + ; + +kwTtl + : K_TTL + ; + +kwType + : K_TYPE + ; + +kwUnlogged + : K_UNLOGGED + ; + +kwUpdate + : K_UPDATE + ; + +kwUse + : K_USE + ; + +kwUser + : K_USER + ; + +kwUsing + : K_USING + ; + +kwValues + : K_VALUES + ; + +kwView + : K_VIEW + ; + +kwWhere + : K_WHERE + ; + +kwWith + : K_WITH + ; + +kwRevoke + : K_REVOKE + ; + +// BRACKETS +// L - left +// R - right +// a - angle +// c - curly +// r - rounded +syntaxBracketLr + : LR_BRACKET + ; + +syntaxBracketRr + : RR_BRACKET + ; + +syntaxBracketLc + : LC_BRACKET + ; + +syntaxBracketRc + : RC_BRACKET + ; + +syntaxBracketLa + : OPERATOR_LT + ; + +syntaxBracketRa + : OPERATOR_GT + ; + +syntaxBracketLs + : LS_BRACKET + ; + +syntaxBracketRs + : RS_BRACKET + ; + +syntaxComma + : COMMA + ; + +syntaxColon + : COLON + ; \ No newline at end of file diff --git a/client-java/controller/src/main/java/org/evomaster/client/java/controller/cassandra/operations/AndOperation.java b/client-java/controller/src/main/java/org/evomaster/client/java/controller/cassandra/operations/AndOperation.java new file mode 100644 index 0000000000..6523b0f5b3 --- /dev/null +++ b/client-java/controller/src/main/java/org/evomaster/client/java/controller/cassandra/operations/AndOperation.java @@ -0,0 +1,19 @@ +package org.evomaster.client.java.controller.cassandra.operations; + +import java.util.List; + +/** + * Represents a CQL AND operation. + * Joins query clauses with the logical AND returns all rows that match the conditions of all clauses. + */ +public class AndOperation extends CqlQueryOperation { + private final List conditions; + + public AndOperation(List conditions) { + this.conditions = conditions; + } + + public List getConditions() { + return conditions; + } +} diff --git a/client-java/controller/src/main/java/org/evomaster/client/java/controller/cassandra/operations/ComparisonOperation.java b/client-java/controller/src/main/java/org/evomaster/client/java/controller/cassandra/operations/ComparisonOperation.java new file mode 100644 index 0000000000..89168e0963 --- /dev/null +++ b/client-java/controller/src/main/java/org/evomaster/client/java/controller/cassandra/operations/ComparisonOperation.java @@ -0,0 +1,22 @@ +package org.evomaster.client.java.controller.cassandra.operations; + +/** + * Represents a comparison operation. + */ +abstract public class ComparisonOperation extends CqlQueryOperation { + private final String columnName; + private final V value; + + ComparisonOperation(String fieldName, V value) { + this.columnName = fieldName; + this.value = value; + } + + public String getColumnName() { + return columnName; + } + + public V getValue() { + return value; + } +} diff --git a/client-java/controller/src/main/java/org/evomaster/client/java/controller/cassandra/operations/ContainsKeyOperation.java b/client-java/controller/src/main/java/org/evomaster/client/java/controller/cassandra/operations/ContainsKeyOperation.java new file mode 100644 index 0000000000..839a5e0ee4 --- /dev/null +++ b/client-java/controller/src/main/java/org/evomaster/client/java/controller/cassandra/operations/ContainsKeyOperation.java @@ -0,0 +1,23 @@ +package org.evomaster.client.java.controller.cassandra.operations; + +/** + * Represents a CQL CONTAINS KEY operation. + * The CONTAINS KEY operator may only be used on map columns and applies to the map keys. + */ +public class ContainsKeyOperation extends CqlQueryOperation { + private final String columnName; + private final V value; + + public ContainsKeyOperation(String columnName, V value) { + this.columnName = columnName; + this.value = value; + } + + public String getColumnName() { + return columnName; + } + + public V getValue() { + return value; + } +} diff --git a/client-java/controller/src/main/java/org/evomaster/client/java/controller/cassandra/operations/ContainsOperation.java b/client-java/controller/src/main/java/org/evomaster/client/java/controller/cassandra/operations/ContainsOperation.java new file mode 100644 index 0000000000..addca04d17 --- /dev/null +++ b/client-java/controller/src/main/java/org/evomaster/client/java/controller/cassandra/operations/ContainsOperation.java @@ -0,0 +1,25 @@ +package org.evomaster.client.java.controller.cassandra.operations; + +/** + * Represents a CQL CONTAINS operation. + * The CONTAINS operator may only be used for collection columns (lists, sets, and maps). + * In the case of maps, CONTAINS applies to the map values. + */ +public class ContainsOperation extends CqlQueryOperation { + private final String columnName; + private final V value; + + public ContainsOperation(String columnName, V value) { + this.columnName = columnName; + this.value = value; + } + + public String getColumnName() { + return columnName; + } + + public V getValue() { + return value; + } + +} diff --git a/client-java/controller/src/main/java/org/evomaster/client/java/controller/cassandra/operations/CqlQueryOperation.java b/client-java/controller/src/main/java/org/evomaster/client/java/controller/cassandra/operations/CqlQueryOperation.java new file mode 100644 index 0000000000..aa06abd98b --- /dev/null +++ b/client-java/controller/src/main/java/org/evomaster/client/java/controller/cassandra/operations/CqlQueryOperation.java @@ -0,0 +1,6 @@ +package org.evomaster.client.java.controller.cassandra.operations; + +/** + * Represents a CQL query operation. + */ +abstract public class CqlQueryOperation {} diff --git a/client-java/controller/src/main/java/org/evomaster/client/java/controller/cassandra/operations/EqualsOperation.java b/client-java/controller/src/main/java/org/evomaster/client/java/controller/cassandra/operations/EqualsOperation.java new file mode 100644 index 0000000000..e4259af623 --- /dev/null +++ b/client-java/controller/src/main/java/org/evomaster/client/java/controller/cassandra/operations/EqualsOperation.java @@ -0,0 +1,7 @@ +package org.evomaster.client.java.controller.cassandra.operations; + +public class EqualsOperation extends ComparisonOperation { + public EqualsOperation(String columnName, V value) { + super(columnName, value); + } +} diff --git a/client-java/controller/src/main/java/org/evomaster/client/java/controller/cassandra/operations/GreaterThanEqualsOperation.java b/client-java/controller/src/main/java/org/evomaster/client/java/controller/cassandra/operations/GreaterThanEqualsOperation.java new file mode 100644 index 0000000000..93e3e0f29b --- /dev/null +++ b/client-java/controller/src/main/java/org/evomaster/client/java/controller/cassandra/operations/GreaterThanEqualsOperation.java @@ -0,0 +1,7 @@ +package org.evomaster.client.java.controller.cassandra.operations; + +public class GreaterThanEqualsOperation extends ComparisonOperation { + public GreaterThanEqualsOperation(String columnName, V value) { + super(columnName, value); + } +} diff --git a/client-java/controller/src/main/java/org/evomaster/client/java/controller/cassandra/operations/GreaterThanOperation.java b/client-java/controller/src/main/java/org/evomaster/client/java/controller/cassandra/operations/GreaterThanOperation.java new file mode 100644 index 0000000000..b98de80818 --- /dev/null +++ b/client-java/controller/src/main/java/org/evomaster/client/java/controller/cassandra/operations/GreaterThanOperation.java @@ -0,0 +1,7 @@ +package org.evomaster.client.java.controller.cassandra.operations; + +public class GreaterThanOperation extends ComparisonOperation { + public GreaterThanOperation(String columnName, V value) { + super(columnName, value); + } +} diff --git a/client-java/controller/src/main/java/org/evomaster/client/java/controller/cassandra/operations/InOperation.java b/client-java/controller/src/main/java/org/evomaster/client/java/controller/cassandra/operations/InOperation.java new file mode 100644 index 0000000000..02b230fc28 --- /dev/null +++ b/client-java/controller/src/main/java/org/evomaster/client/java/controller/cassandra/operations/InOperation.java @@ -0,0 +1,29 @@ +package org.evomaster.client.java.controller.cassandra.operations; + +import java.util.List; + +/** + * Represents a CQL IN operation for a single column. + * + *
+ * WHERE userid IN ('john', 'jane')
+ * 
+ */ +public class InOperation extends CqlQueryOperation { + + private final String columnName; + private final List values; + + public InOperation(String columnName, List values) { + this.columnName = columnName; + this.values = values; + } + + public String getColumnName() { + return columnName; + } + + public List getValues() { + return values; + } +} \ No newline at end of file diff --git a/client-java/controller/src/main/java/org/evomaster/client/java/controller/cassandra/operations/LessThanEqualsOperation.java b/client-java/controller/src/main/java/org/evomaster/client/java/controller/cassandra/operations/LessThanEqualsOperation.java new file mode 100644 index 0000000000..e4f0a2860a --- /dev/null +++ b/client-java/controller/src/main/java/org/evomaster/client/java/controller/cassandra/operations/LessThanEqualsOperation.java @@ -0,0 +1,7 @@ +package org.evomaster.client.java.controller.cassandra.operations; + +public class LessThanEqualsOperation extends ComparisonOperation { + public LessThanEqualsOperation(String columnName, V value) { + super(columnName, value); + } +} diff --git a/client-java/controller/src/main/java/org/evomaster/client/java/controller/cassandra/operations/LessThanOperation.java b/client-java/controller/src/main/java/org/evomaster/client/java/controller/cassandra/operations/LessThanOperation.java new file mode 100644 index 0000000000..00b1c7a32e --- /dev/null +++ b/client-java/controller/src/main/java/org/evomaster/client/java/controller/cassandra/operations/LessThanOperation.java @@ -0,0 +1,7 @@ +package org.evomaster.client.java.controller.cassandra.operations; + +public class LessThanOperation extends ComparisonOperation { + public LessThanOperation(String columnName, V value) { + super(columnName, value); + } +} diff --git a/client-java/controller/src/main/java/org/evomaster/client/java/controller/cassandra/parser/CqlParserUtils.java b/client-java/controller/src/main/java/org/evomaster/client/java/controller/cassandra/parser/CqlParserUtils.java new file mode 100644 index 0000000000..741a4e110d --- /dev/null +++ b/client-java/controller/src/main/java/org/evomaster/client/java/controller/cassandra/parser/CqlParserUtils.java @@ -0,0 +1,125 @@ +package org.evomaster.client.java.controller.cassandra.parser; + +import org.antlr.v4.runtime.CharStreams; +import org.antlr.v4.runtime.CommonTokenStream; +import org.evomaster.client.java.controller.cassandra.operations.*; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +public class CqlParserUtils { + + private CqlParserUtils() {} + + public static CqlParser.RootContext parseCqlCommand(String cqlCommand) { + CqlLexer lexer = new CqlLexer(CharStreams.fromString(cqlCommand)); + CqlParser parser = new CqlParser(new CommonTokenStream(lexer)); + return parser.root(); + } + + public static boolean canParseCqlCommand(String cqlCommand) { + try { + CqlParser.RootContext root = parseCqlCommand(cqlCommand); + return root.exception == null && root.cqls() != null && root.cqls().cql(0) != null; + } catch (Exception e) { + return false; + } + } + + public static boolean isSelect(String cqlCommand) { + return cqlCommand.trim().toUpperCase().startsWith("SELECT"); + } + + public static boolean isUpdate(String cqlCommand) { + return cqlCommand.trim().toUpperCase().startsWith("UPDATE"); + } + + public static boolean isDelete(String cqlCommand) { + return cqlCommand.trim().toUpperCase().startsWith("DELETE"); + } + + public static CqlParser.WhereSpecContext getWhereSpec(CqlParser.RootContext root) { + CqlParser.CqlContext cql = root.cqls() != null ? root.cqls().cql(0) : null; + if (cql == null) return null; + if (cql.select_() != null) return cql.select_().whereSpec(); + if (cql.update() != null) return cql.update().whereSpec(); + if (cql.delete_() != null) return cql.delete_().whereSpec(); + return null; + } + + /** + * Parses the WHERE clause of a CQL SELECT, UPDATE, or DELETE and returns the + * corresponding operation tree. Multiple AND-joined conditions are wrapped in + * an {@link AndOperation}; a single condition is returned directly; null is + * returned when no WHERE clause is present. + */ + public static CqlQueryOperation getWhereOperation(CqlParser.RootContext root) { + CqlParser.WhereSpecContext whereSpec = getWhereSpec(root); + if (whereSpec == null) return null; + + List elements = whereSpec.relationElements().relationElement(); + if (elements.isEmpty()) return null; + if (elements.size() == 1) return parseRelationElement(elements.get(0)); + + List ops = new ArrayList<>(); + for (CqlParser.RelationElementContext el : elements) { + CqlQueryOperation op = parseRelationElement(el); + if (op != null) ops.add(op); + } + return new AndOperation(ops); + } + + private static CqlQueryOperation parseRelationElement(CqlParser.RelationElementContext rel) { + // CONTAINS KEY: col CONTAINS KEY value + if (rel.relalationContainsKey() != null) { + CqlParser.RelalationContainsKeyContext ck = rel.relalationContainsKey(); + return new ContainsKeyOperation<>(ck.OBJECT_NAME().getText(), parseConstant(ck.constant())); + } + + // CONTAINS: col CONTAINS value + if (rel.relalationContains() != null) { + CqlParser.RelalationContainsContext c = rel.relalationContains(); + return new ContainsOperation<>(c.OBJECT_NAME().getText(), parseConstant(c.constant())); + } + + // IN: col IN (v1, v2, ...) + if (rel.kwIn() != null) { + String col = rel.OBJECT_NAME(0).getText(); + List values = new ArrayList<>(); + if (rel.functionArgs() != null) { + for (CqlParser.ConstantContext cc : rel.functionArgs().constant()) { + values.add(parseConstant(cc)); + } + } + return new InOperation(col, values); + } + + // Comparison: col OP constant + CqlParser.ConstantContext constant = rel.constant(); + if (constant != null && rel.OBJECT_NAME(0) != null) { + String col = rel.OBJECT_NAME(0).getText(); + Object value = parseConstant(constant); + if (rel.OPERATOR_EQ() != null) return new EqualsOperation<>(col, value); + if (rel.OPERATOR_GT() != null) return new GreaterThanOperation<>(col, value); + if (rel.OPERATOR_GTE() != null) return new GreaterThanEqualsOperation<>(col, value); + if (rel.OPERATOR_LT() != null) return new LessThanOperation<>(col, value); + if (rel.OPERATOR_LTE() != null) return new LessThanEqualsOperation<>(col, value); + } + + return null; + } + + private static Object parseConstant(CqlParser.ConstantContext ctx) { + if (ctx.UUID() != null) return UUID.fromString(ctx.UUID().getText()); + if (ctx.stringLiteral() != null) { + String raw = ctx.stringLiteral().getText(); + return raw.substring(1, raw.length() - 1); // strip surrounding single quotes + } + if (ctx.decimalLiteral() != null) return Long.parseLong(ctx.decimalLiteral().getText()); + if (ctx.floatLiteral() != null) return Double.parseDouble(ctx.floatLiteral().getText()); + if (ctx.booleanLiteral() != null) return ctx.booleanLiteral().getText().equalsIgnoreCase("true"); + if (ctx.durationLiteral() != null) return ctx.durationLiteral().getText(); + return null; // kwNull, codeBlock, hexadecimal + } +} \ No newline at end of file diff --git a/client-java/controller/src/test/java/org/evomaster/client/java/controller/cassandra/parser/CqlParserUtilsTest.java b/client-java/controller/src/test/java/org/evomaster/client/java/controller/cassandra/parser/CqlParserUtilsTest.java new file mode 100644 index 0000000000..06d53efc09 --- /dev/null +++ b/client-java/controller/src/test/java/org/evomaster/client/java/controller/cassandra/parser/CqlParserUtilsTest.java @@ -0,0 +1,462 @@ +package org.evomaster.client.java.controller.cassandra.parser; + +import org.evomaster.client.java.controller.cassandra.operations.*; +import org.junit.jupiter.api.Test; + +import java.util.Arrays; +import java.util.List; +import java.util.UUID; + +import static org.junit.jupiter.api.Assertions.*; + +public class CqlParserUtilsTest { + + // ------------------------------------------------------------------------- + // Helper + // ------------------------------------------------------------------------- + + private static CqlQueryOperation parseWhere(String cql) { + return CqlParserUtils.getWhereOperation(CqlParserUtils.parseCqlCommand(cql)); + } + + private static Object extractValue(CqlQueryOperation op) { + return ((ComparisonOperation) op).getValue(); + } + + private static String extractColumn(CqlQueryOperation op) { + return ((ComparisonOperation) op).getColumnName(); + } + + // ------------------------------------------------------------------------- + // isSelect / isUpdate / isDelete + // ------------------------------------------------------------------------- + + @Test + void isSelect_trueForSelectQuery() { + assertTrue(CqlParserUtils.isSelect("SELECT * FROM t")); + } + + @Test + void isSelect_caseInsensitive() { + assertTrue(CqlParserUtils.isSelect("select * from t")); + } + + @Test + void isSelect_falseForUpdate() { + assertFalse(CqlParserUtils.isSelect("UPDATE t SET col = 1 WHERE id = 1")); + } + + @Test + void isUpdate_trueForUpdateQuery() { + assertTrue(CqlParserUtils.isUpdate("UPDATE t SET col = 1 WHERE id = 1")); + } + + @Test + void isDelete_trueForDeleteQuery() { + assertTrue(CqlParserUtils.isDelete("DELETE FROM t WHERE id = 1")); + } + + // ------------------------------------------------------------------------- + // canParseCqlCommand + // ------------------------------------------------------------------------- + + @Test + void canParse_validSelect() { + assertTrue(CqlParserUtils.canParseCqlCommand("SELECT * FROM t WHERE id = 1")); + } + + @Test + void canParse_validSelectNoWhere() { + assertTrue(CqlParserUtils.canParseCqlCommand("SELECT * FROM t")); + } + + @Test + void canParse_invalidQuery_returnsFalse() { + assertFalse(CqlParserUtils.canParseCqlCommand("THIS IS NOT A CQL QUERY")); + } + + // ------------------------------------------------------------------------- + // No WHERE clause → null + // ------------------------------------------------------------------------- + + @Test + void getWhereOperation_noWhereClause_returnsNull() { + assertNull(parseWhere("SELECT * FROM t")); + } + + @Test + void getWhereOperation_updateNoWhere_returnsNull() { + // a bare UPDATE without WHERE is invalid CQL, but getWhereSpec should still return null + CqlParser.RootContext root = CqlParserUtils.parseCqlCommand("SELECT * FROM t"); + assertNull(CqlParserUtils.getWhereOperation(root)); + } + + // ------------------------------------------------------------------------- + // EqualsOperation + // ------------------------------------------------------------------------- + + @Test + void equals_stringValue() { + CqlQueryOperation op = parseWhere("SELECT * FROM t WHERE col = 'hello'"); + assertInstanceOf(EqualsOperation.class, op); + assertEquals("col", extractColumn(op)); + assertEquals("hello", extractValue(op)); + } + + @Test + void equals_longValue() { + CqlQueryOperation op = parseWhere("SELECT * FROM t WHERE col = 42"); + assertInstanceOf(EqualsOperation.class, op); + assertEquals("col", extractColumn(op)); + assertEquals(42L, extractValue(op)); + } + + @Test + void equals_booleanTrue() { + CqlQueryOperation op = parseWhere("SELECT * FROM t WHERE col = true"); + assertInstanceOf(EqualsOperation.class, op); + assertEquals("col", extractColumn(op)); + assertEquals(Boolean.TRUE, extractValue(op)); + } + + @Test + void equals_booleanFalse() { + CqlQueryOperation op = parseWhere("SELECT * FROM t WHERE col = false"); + assertInstanceOf(EqualsOperation.class, op); + assertEquals("col", extractColumn(op)); + assertEquals(Boolean.FALSE, extractValue(op)); + } + + @Test + void equals_uuid() { + String rawUuid = "550e8400-e29b-41d4-a716-446655440000"; + CqlQueryOperation op = parseWhere("SELECT * FROM t WHERE col = " + rawUuid); + assertInstanceOf(EqualsOperation.class, op); + assertEquals("col", extractColumn(op)); + assertEquals(UUID.fromString(rawUuid), extractValue(op)); + } + + @Test + void equals_doubleValue() { + CqlQueryOperation op = parseWhere("SELECT * FROM t WHERE col = 3.14"); + assertInstanceOf(EqualsOperation.class, op); + assertEquals("col", extractColumn(op)); + assertEquals(3.14, extractValue(op)); + } + + @Test + void equals_nullValue() { + CqlQueryOperation op = parseWhere("SELECT * FROM t WHERE col = NULL"); + assertInstanceOf(EqualsOperation.class, op); + assertEquals("col", extractColumn(op)); + assertNull(extractValue(op)); + } + + // ------------------------------------------------------------------------- + // GreaterThanOperation + // ------------------------------------------------------------------------- + + @Test + void greaterThan_longValue() { + CqlQueryOperation op = parseWhere("SELECT * FROM t WHERE col > 10"); + assertInstanceOf(GreaterThanOperation.class, op); + assertEquals("col", extractColumn(op)); + assertEquals(10L, extractValue(op)); + } + + // ------------------------------------------------------------------------- + // GreaterThanEqualsOperation + // ------------------------------------------------------------------------- + + @Test + void greaterThanEquals_longValue() { + CqlQueryOperation op = parseWhere("SELECT * FROM t WHERE col >= 10"); + assertInstanceOf(GreaterThanEqualsOperation.class, op); + assertEquals("col", extractColumn(op)); + assertEquals(10L, extractValue(op)); + } + + // ------------------------------------------------------------------------- + // LessThanOperation + // ------------------------------------------------------------------------- + + @Test + void lessThan_longValue() { + CqlQueryOperation op = parseWhere("SELECT * FROM t WHERE col < 10"); + assertInstanceOf(LessThanOperation.class, op); + assertEquals("col", extractColumn(op)); + assertEquals(10L, extractValue(op)); + } + + // ------------------------------------------------------------------------- + // LessThanEqualsOperation + // ------------------------------------------------------------------------- + + @Test + void lessThanEquals_longValue() { + CqlQueryOperation op = parseWhere("SELECT * FROM t WHERE col <= 10"); + assertInstanceOf(LessThanEqualsOperation.class, op); + assertEquals("col", extractColumn(op)); + assertEquals(10L, extractValue(op)); + } + + // ------------------------------------------------------------------------- + // InOperation + // ------------------------------------------------------------------------- + + @Test + void in_multipleStringValues() { + CqlQueryOperation op = parseWhere("SELECT * FROM t WHERE col IN ('a', 'b', 'c')"); + assertInstanceOf(InOperation.class, op); + InOperation in = (InOperation) op; + assertEquals("col", in.getColumnName()); + assertEquals(Arrays.asList("a", "b", "c"), in.getValues()); + } + + @Test + void in_multipleLongValues() { + CqlQueryOperation op = parseWhere("SELECT * FROM t WHERE col IN (1, 2, 3)"); + assertInstanceOf(InOperation.class, op); + InOperation in = (InOperation) op; + assertEquals("col", in.getColumnName()); + assertEquals(Arrays.asList(1L, 2L, 3L), in.getValues()); + } + + @Test + void in_emptyList() { + CqlQueryOperation op = parseWhere("SELECT * FROM t WHERE col IN ()"); + assertInstanceOf(InOperation.class, op); + InOperation in = (InOperation) op; + assertEquals("col", in.getColumnName()); + assertTrue(in.getValues().isEmpty()); + } + + // ------------------------------------------------------------------------- + // ContainsOperation + // ------------------------------------------------------------------------- + + @Test + void contains_stringValue() { + CqlQueryOperation op = parseWhere("SELECT * FROM t WHERE col CONTAINS 'value'"); + assertInstanceOf(ContainsOperation.class, op); + ContainsOperation c = (ContainsOperation) op; + assertEquals("col", c.getColumnName()); + assertEquals("value", c.getValue()); + } + + @Test + void contains_longValue() { + CqlQueryOperation op = parseWhere("SELECT * FROM t WHERE col CONTAINS 99"); + assertInstanceOf(ContainsOperation.class, op); + assertEquals("col", ((ContainsOperation) op).getColumnName()); + assertEquals(99L, ((ContainsOperation) op).getValue()); + } + + // ------------------------------------------------------------------------- + // ContainsKeyOperation + // ------------------------------------------------------------------------- + + @Test + void containsKey_stringValue() { + CqlQueryOperation op = parseWhere("SELECT * FROM t WHERE col CONTAINS KEY 'myKey'"); + assertInstanceOf(ContainsKeyOperation.class, op); + ContainsKeyOperation ck = (ContainsKeyOperation) op; + assertEquals("col", ck.getColumnName()); + assertEquals("myKey", ck.getValue()); + } + + @Test + void containsKey_longValue() { + CqlQueryOperation op = parseWhere("SELECT * FROM t WHERE col CONTAINS KEY 7"); + assertInstanceOf(ContainsKeyOperation.class, op); + assertEquals("col", ((ContainsKeyOperation) op).getColumnName()); + assertEquals(7L, ((ContainsKeyOperation) op).getValue()); + } + + // ------------------------------------------------------------------------- + // AndOperation + // ------------------------------------------------------------------------- + + @Test + void and_twoConditions() { + CqlQueryOperation op = parseWhere("SELECT * FROM t WHERE a = 1 AND b = 'hello'"); + assertInstanceOf(AndOperation.class, op); + List conditions = ((AndOperation) op).getConditions(); + assertEquals(2, conditions.size()); + assertInstanceOf(EqualsOperation.class, conditions.get(0)); + assertInstanceOf(EqualsOperation.class, conditions.get(1)); + assertEquals("a", ((EqualsOperation) conditions.get(0)).getColumnName()); + assertEquals(1L, ((EqualsOperation) conditions.get(0)).getValue()); + assertEquals("b", ((EqualsOperation) conditions.get(1)).getColumnName()); + assertEquals("hello", ((EqualsOperation) conditions.get(1)).getValue()); + } + + @Test + void and_threeConditions_mixedOperators() { + CqlQueryOperation op = parseWhere( + "SELECT * FROM t WHERE a = 1 AND b > 2 AND c <= 3"); + assertInstanceOf(AndOperation.class, op); + List conditions = ((AndOperation) op).getConditions(); + assertEquals(3, conditions.size()); + assertInstanceOf(EqualsOperation.class, conditions.get(0)); + assertInstanceOf(GreaterThanOperation.class, conditions.get(1)); + assertInstanceOf(LessThanEqualsOperation.class, conditions.get(2)); + assertEquals("a", ((ComparisonOperation) conditions.get(0)).getColumnName()); + assertEquals(1L, ((ComparisonOperation) conditions.get(0)).getValue()); + assertEquals("b", ((ComparisonOperation) conditions.get(1)).getColumnName()); + assertEquals(2L, ((ComparisonOperation) conditions.get(1)).getValue()); + assertEquals("c", ((ComparisonOperation) conditions.get(2)).getColumnName()); + assertEquals(3L, ((ComparisonOperation) conditions.get(2)).getValue()); + } + + // ------------------------------------------------------------------------- + // Quoted identifiers + // ------------------------------------------------------------------------- + + @Test + void quotedColumnName_equals_includesQuotesInName() { + CqlQueryOperation op = parseWhere("SELECT * FROM t WHERE \"myCol\" = 42"); + assertInstanceOf(EqualsOperation.class, op); + // OBJECT_NAME token text includes the surrounding double quotes + assertEquals("\"myCol\"", extractColumn(op)); + assertEquals(42L, extractValue(op)); + } + + @Test + void quotedColumnName_greaterThan() { + CqlQueryOperation op = parseWhere("SELECT * FROM t WHERE \"amount\" > 100"); + assertInstanceOf(GreaterThanOperation.class, op); + assertEquals("\"amount\"", extractColumn(op)); + assertEquals(100L, extractValue(op)); + } + + @Test + void quotedColumnName_in() { + CqlQueryOperation op = parseWhere("SELECT * FROM t WHERE \"status\" IN ('active', 'pending')"); + assertInstanceOf(InOperation.class, op); + InOperation in = (InOperation) op; + assertEquals("\"status\"", in.getColumnName()); + assertEquals(Arrays.asList("active", "pending"), in.getValues()); + } + + @Test + void quotedColumnName_contains() { + CqlQueryOperation op = parseWhere("SELECT * FROM t WHERE \"tags\" CONTAINS 'java'"); + assertInstanceOf(ContainsOperation.class, op); + ContainsOperation c = (ContainsOperation) op; + assertEquals("\"tags\"", c.getColumnName()); + assertEquals("java", c.getValue()); + } + + @Test + void quotedColumnName_containsKey() { + CqlQueryOperation op = parseWhere("SELECT * FROM t WHERE \"meta\" CONTAINS KEY 'env'"); + assertInstanceOf(ContainsKeyOperation.class, op); + ContainsKeyOperation ck = (ContainsKeyOperation) op; + assertEquals("\"meta\"", ck.getColumnName()); + assertEquals("env", ck.getValue()); + } + + // ------------------------------------------------------------------------- + // Value type parsing — time-related types arrive as string literals in CQL + // ------------------------------------------------------------------------- + + @Test + void parse_dateStringLiteral() { + // CQL dates are written as single-quoted string literals + CqlQueryOperation op = parseWhere("SELECT * FROM t WHERE d = '2023-01-15'"); + assertInstanceOf(EqualsOperation.class, op); + assertEquals("d", extractColumn(op)); + assertEquals("2023-01-15", extractValue(op)); + } + + @Test + void parse_timeStringLiteral() { + CqlQueryOperation op = parseWhere("SELECT * FROM t WHERE time_col = '14:30:00'"); + assertInstanceOf(EqualsOperation.class, op); + assertEquals("time_col", extractColumn(op)); + assertEquals("14:30:00", extractValue(op)); + } + + @Test + void parse_timestampStringLiteral() { + CqlQueryOperation op = parseWhere("SELECT * FROM t WHERE ts = '2023-01-15T14:30:00Z'"); + assertInstanceOf(EqualsOperation.class, op); + assertEquals("ts", extractColumn(op)); + assertEquals("2023-01-15T14:30:00Z", extractValue(op)); + } + + // ------------------------------------------------------------------------- + // Value type parsing — duration literals + // ------------------------------------------------------------------------- + + @Test + void parse_durationStandardFormat() { + // standard quantity-unit: 89h4m48s + CqlQueryOperation op = parseWhere("SELECT * FROM t WHERE d = 89h4m48s"); + assertInstanceOf(EqualsOperation.class, op); + assertEquals("d", extractColumn(op)); + assertEquals("89h4m48s", extractValue(op)); + } + + @Test + void parse_durationWithMonths() { + // standard: 1y2mo3d + CqlQueryOperation op = parseWhere("SELECT * FROM t WHERE d = 1y2mo3d"); + assertInstanceOf(EqualsOperation.class, op); + assertEquals("d", extractColumn(op)); + assertEquals("1y2mo3d", extractValue(op)); + } + + @Test + void parse_durationISO8601() { + // ISO 8601: PT89H8M53S + CqlQueryOperation op = parseWhere("SELECT * FROM t WHERE d = PT89H8M53S"); + assertInstanceOf(EqualsOperation.class, op); + assertEquals("d", extractColumn(op)); + assertEquals("PT89H8M53S", extractValue(op)); + } + + @Test + void parse_durationISO8601_full() { + // ISO 8601: P1Y2M3DT4H5M6S + CqlQueryOperation op = parseWhere("SELECT * FROM t WHERE d = P1Y2M3DT4H5M6S"); + assertInstanceOf(EqualsOperation.class, op); + assertEquals("d", extractColumn(op)); + assertEquals("P1Y2M3DT4H5M6S", extractValue(op)); + } + + // ------------------------------------------------------------------------- + // WHERE clause on UPDATE and DELETE + // ------------------------------------------------------------------------- + + @Test + void update_whereClause_parsedCorrectly() { + CqlQueryOperation op = parseWhere( + "UPDATE t SET val = 'x' WHERE id = 99"); + assertInstanceOf(EqualsOperation.class, op); + assertEquals("id", extractColumn(op)); + assertEquals(99L, extractValue(op)); + } + + @Test + void delete_whereClause_parsedCorrectly() { + CqlQueryOperation op = parseWhere("DELETE FROM t WHERE id = 7"); + assertInstanceOf(EqualsOperation.class, op); + assertEquals("id", extractColumn(op)); + assertEquals(7L, extractValue(op)); + } + + @Test + void delete_whereClause_andCondition() { + CqlQueryOperation op = parseWhere( + "DELETE FROM t WHERE partition_key = 1 AND clustering_key = 'abc'"); + assertInstanceOf(AndOperation.class, op); + List conditions = ((AndOperation) op).getConditions(); + assertEquals(2, conditions.size()); + assertEquals("partition_key", ((EqualsOperation) conditions.get(0)).getColumnName()); + assertEquals(1L, ((EqualsOperation) conditions.get(0)).getValue()); + assertEquals("clustering_key", ((EqualsOperation) conditions.get(1)).getColumnName()); + assertEquals("abc", ((EqualsOperation) conditions.get(1)).getValue()); + } +} \ No newline at end of file