Skip to content

Commit

Permalink
STAR-1097 Store Raw CQL query inside statement (apache#333)
Browse files Browse the repository at this point in the history
Original CQL string is needed in the implementation of Query
intercepter (STAR-1112). Converged Cassandra stored it in
QueryHandler.Prepared, which is difficult to access. It seems that it
is more straightforward to move storing CQL string into statements.

This commit changes to store query strings in statements and adds an
access method to the string to CQLStatement.
  • Loading branch information
k-rus committed Feb 11, 2022
1 parent 326d847 commit ab7fbd2
Show file tree
Hide file tree
Showing 37 changed files with 375 additions and 293 deletions.
9 changes: 5 additions & 4 deletions src/java/org/apache/cassandra/auth/CassandraAuthorizer.java
Expand Up @@ -178,10 +178,11 @@ public void revokeAllOn(IResource droppedResource)
private void executeLoggedBatch(List<CQLStatement> statements)
throws RequestExecutionException, RequestValidationException
{
BatchStatement batch = new BatchStatement(BatchStatement.Type.LOGGED,
VariableSpecifications.empty(),
Lists.newArrayList(Iterables.filter(statements, ModificationStatement.class)),
Attributes.none());
BatchStatement batch = new BatchStatement(null,
BatchStatement.Type.LOGGED,
VariableSpecifications.empty(),
Lists.newArrayList(Iterables.filter(statements, ModificationStatement.class)),
Attributes.none());
processBatch(batch);
}

Expand Down
19 changes: 19 additions & 0 deletions src/java/org/apache/cassandra/cql3/CQLStatement.java
Expand Up @@ -28,6 +28,14 @@

public interface CQLStatement
{
/**
* The query string that produced that statement, if available.
*
* @return the raw query string that produced that statement, or {@code null} if said string is not available
* (typically because the statement has not be built from a string). Note that said string may contain bind markers.
*/
public String getRawCQLStatement();

/**
* Returns all bind variables for the statement
*/
Expand Down Expand Up @@ -101,8 +109,19 @@ default public boolean hasConditions()

public static abstract class Raw
{
protected String rawCQLStatement;
protected VariableSpecifications bindVariables;

public void setRawCQLStatement(String queryString)
{
this.rawCQLStatement = queryString;
}

public String getRawCQLStatement()
{
return rawCQLStatement;
}

public void setBindVariables(List<ColumnIdentifier> variables)
{
bindVariables = new VariableSpecifications(variables);
Expand Down
8 changes: 4 additions & 4 deletions src/java/org/apache/cassandra/cql3/QueryEvents.java
Expand Up @@ -112,14 +112,14 @@ public void notifyQueryFailure(CQLStatement statement,
}

public void notifyExecuteSuccess(CQLStatement statement,
String query,
QueryOptions options,
QueryState state,
long queryTime,
Message.Response response)
{
try
{
String query = statement.getRawCQLStatement();
final String possiblyObfuscatedQuery = listeners.size() > 0 ? possiblyObfuscateQuery(statement, query) : query;
for (Listener listener : listeners)
listener.executeSuccess(statement, possiblyObfuscatedQuery, options, state, queryTime, response);
Expand All @@ -137,7 +137,7 @@ public void notifyExecuteFailure(QueryHandler.Prepared prepared,
Exception cause)
{
CQLStatement statement = prepared != null ? prepared.statement : null;
String query = prepared != null ? prepared.rawCQLStatement : null;
String query = prepared != null ? prepared.statement.getRawCQLStatement() : null;
try
{
final String possiblyObfuscatedQuery = listeners.size() > 0 ? possiblyObfuscateQuery(statement, query) : query;
Expand Down Expand Up @@ -188,7 +188,7 @@ public void notifyBatchFailure(List<QueryHandler.Prepared> prepared,
{
prepared.forEach(p -> {
statements.add(p.statement);
queries.add(p.rawCQLStatement);
queries.add(p.statement.getRawCQLStatement());
});
}
try
Expand Down Expand Up @@ -250,7 +250,7 @@ public void notifyPrepareFailure(@Nullable CQLStatement statement, String query,
}
}

private String possiblyObfuscateQuery(CQLStatement statement, String query)
private String possiblyObfuscateQuery(@Nullable CQLStatement statement, String query)
{
// Statement might be null as side-effect of failed parsing, originates from QueryMessage#execute
return null == statement || statement instanceof AuthenticationStatement ? passwordObfuscator.obfuscate(query) : query;
Expand Down
13 changes: 0 additions & 13 deletions src/java/org/apache/cassandra/cql3/QueryHandler.java
Expand Up @@ -62,22 +62,9 @@ public static class Prepared

public final MD5Digest resultMetadataId;

/**
* Contains the CQL statement source if the statement has been "regularly" perpared via
* {@link QueryHandler#prepare(String, ClientState, Map)}.
* Other usages of this class may or may not contain the CQL statement source.
*/
public final String rawCQLStatement;

public Prepared(CQLStatement statement)
{
this(statement, "");
}

public Prepared(CQLStatement statement, String rawCQLStatement)
{
this.statement = statement;
this.rawCQLStatement = rawCQLStatement;
this.resultMetadataId = ResultSet.ResultMetadata.fromPrepared(statement).getResultMetadataId();
}
}
Expand Down
10 changes: 6 additions & 4 deletions src/java/org/apache/cassandra/cql3/QueryProcessor.java
Expand Up @@ -441,7 +441,7 @@ public static ResultMessage.Prepared prepare(String queryString, ClientState cli
return existing;

CQLStatement statement = getStatement(queryString, clientState);
Prepared prepared = new Prepared(statement, queryString);
Prepared prepared = new Prepared(statement);

int boundTerms = statement.getBindVariables().size();
if (boundTerms > FBUtilities.MAX_UNSIGNED_SHORT)
Expand All @@ -464,8 +464,8 @@ private static ResultMessage.Prepared getStoredPreparedStatement(String queryStr
if (existing == null)
return null;

checkTrue(queryString.equals(existing.rawCQLStatement),
String.format("MD5 hash collision: query with the same MD5 hash was already prepared. \n Existing: '%s'", existing.rawCQLStatement));
checkTrue(queryString.equals(existing.statement.getRawCQLStatement()),
String.format("MD5 hash collision: query with the same MD5 hash was already prepared. \n Existing: '%s'", existing.statement.getRawCQLStatement()));

ResultSet.PreparedMetadata preparedMetadata = ResultSet.PreparedMetadata.fromPrepared(existing.statement);
ResultSet.ResultMetadata resultMetadata = ResultSet.ResultMetadata.fromPrepared(existing.statement);
Expand Down Expand Up @@ -578,7 +578,9 @@ public static CQLStatement.Raw parseStatement(String queryStr) throws SyntaxExce
{
try
{
return CQLFragmentParser.parseAnyUnhandled(CqlParser::query, queryStr);
CQLStatement.Raw stmt = CQLFragmentParser.parseAnyUnhandled(CqlParser::query, queryStr);
stmt.setRawCQLStatement(queryStr);
return stmt;
}
catch (CassandraException ce)
{
Expand Down
16 changes: 11 additions & 5 deletions src/java/org/apache/cassandra/cql3/statements/BatchStatement.java
Expand Up @@ -39,7 +39,6 @@

import org.apache.cassandra.audit.AuditLogContext;
import org.apache.cassandra.audit.AuditLogEntryType;
import org.apache.cassandra.config.DatabaseDescriptor;
import org.apache.cassandra.cql3.Attributes;
import org.apache.cassandra.cql3.BatchQueryOptions;
import org.apache.cassandra.cql3.CQLStatement;
Expand Down Expand Up @@ -69,9 +68,7 @@
import org.apache.cassandra.service.ClientWarn;
import org.apache.cassandra.service.QueryState;
import org.apache.cassandra.service.StorageProxy;
import org.apache.cassandra.tracing.Tracing;
import org.apache.cassandra.transport.messages.ResultMessage;
import org.apache.cassandra.utils.FBUtilities;
import org.apache.cassandra.utils.NoSpamLogger;
import org.apache.cassandra.utils.Pair;

Expand All @@ -88,6 +85,7 @@ public enum Type
LOGGED, UNLOGGED, COUNTER
}

private final String rawCQLStatement;
public final Type type;
private final VariableSpecifications bindVariables;
private final List<ModificationStatement> statements;
Expand Down Expand Up @@ -120,8 +118,10 @@ public enum Type
* @param statements the list of statements in the batch
* @param attrs additional attributes for statement (CL, timestamp, timeToLive)
*/
public BatchStatement(Type type, VariableSpecifications bindVariables, List<ModificationStatement> statements, Attributes attrs)
public BatchStatement(String queryString, Type type, VariableSpecifications bindVariables,
List<ModificationStatement> statements, Attributes attrs)
{
this.rawCQLStatement = queryString;
this.type = type;
this.bindVariables = bindVariables;
this.statements = statements;
Expand Down Expand Up @@ -155,6 +155,12 @@ public BatchStatement(Type type, VariableSpecifications bindVariables, List<Modi
this.updatesVirtualTables = updatesVirtualTables;
}

@Override
public String getRawCQLStatement()
{
return rawCQLStatement;
}

@Override
public List<ColumnSpecification> getBindVariables()
{
Expand Down Expand Up @@ -643,7 +649,7 @@ public BatchStatement prepare(ClientState state)
Attributes prepAttrs = attrs.prepare("[batch]", "[batch]");
prepAttrs.collectMarkerSpecification(bindVariables);

BatchStatement batchStatement = new BatchStatement(type, bindVariables, statements, prepAttrs);
BatchStatement batchStatement = new BatchStatement(rawCQLStatement, type, bindVariables, statements, prepAttrs);
batchStatement.validate();

return batchStatement;
Expand Down
28 changes: 15 additions & 13 deletions src/java/org/apache/cassandra/cql3/statements/DeleteStatement.java
Expand Up @@ -43,14 +43,15 @@
*/
public class DeleteStatement extends ModificationStatement
{
private DeleteStatement(VariableSpecifications bindVariables,
TableMetadata cfm,
Operations operations,
StatementRestrictions restrictions,
Conditions conditions,
Attributes attrs)
private DeleteStatement(String queryString,
VariableSpecifications bindVariables,
TableMetadata cfm,
Operations operations,
StatementRestrictions restrictions,
Conditions conditions,
Attributes attrs)
{
super(StatementType.DELETE, bindVariables, cfm, operations, restrictions, conditions, attrs);
super(queryString, StatementType.DELETE, bindVariables, cfm, operations, restrictions, conditions, attrs);
}

@Override
Expand Down Expand Up @@ -168,12 +169,13 @@ protected ModificationStatement prepareInternal(TableMetadata metadata,
whereClause,
conditions);

DeleteStatement stmt = new DeleteStatement(bindVariables,
metadata,
operations,
restrictions,
conditions,
attrs);
DeleteStatement stmt = new DeleteStatement(rawCQLStatement,
bindVariables,
metadata,
operations,
restrictions,
conditions,
attrs);

if (stmt.hasConditions() && !restrictions.hasAllPKColumnsRestrictedByEqualities())
{
Expand Down
Expand Up @@ -78,6 +78,8 @@ public abstract class ModificationStatement implements CQLStatement

private static final ColumnIdentifier CAS_RESULT_COLUMN = new ColumnIdentifier("[applied]", false);

private final String rawCQLStatement;

protected final StatementType type;

protected final VariableSpecifications bindVariables;
Expand All @@ -97,14 +99,16 @@ public abstract class ModificationStatement implements CQLStatement

private final RegularAndStaticColumns requiresRead;

public ModificationStatement(StatementType type,
VariableSpecifications bindVariables,
TableMetadata metadata,
Operations operations,
StatementRestrictions restrictions,
Conditions conditions,
Attributes attrs)
public ModificationStatement(String queryString,
StatementType type,
VariableSpecifications bindVariables,
TableMetadata metadata,
Operations operations,
StatementRestrictions restrictions,
Conditions conditions,
Attributes attrs)
{
this.rawCQLStatement = queryString;
this.type = type;
this.bindVariables = bindVariables;
this.metadata = metadata;
Expand Down Expand Up @@ -152,6 +156,12 @@ public ModificationStatement(StatementType type,
this.requiresRead = requiresReadBuilder.build();
}

@Override
public String getRawCQLStatement()
{
return rawCQLStatement;
}

@Override
public List<ColumnSpecification> getBindVariables()
{
Expand Down

0 comments on commit ab7fbd2

Please sign in to comment.