Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,9 @@ public AbstractType<?> getExactTypeIfKnown(String keyspace)

public String getText()
{
return name + terms.stream().map(Term.Raw::getText).collect(Collectors.joining(", ", "(", ")"));
CqlBuilder cqlNameBuilder = new CqlBuilder();
name.appendCqlTo(cqlNameBuilder);
return cqlNameBuilder + terms.stream().map(Term.Raw::getText).collect(Collectors.joining(", ", "(", ")"));
}
}
}
132 changes: 132 additions & 0 deletions test/unit/org/apache/cassandra/cql3/ViewTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

import com.google.common.util.concurrent.Uninterruptibles;

Expand All @@ -37,6 +38,9 @@
import org.apache.cassandra.db.SystemKeyspace;
import org.apache.cassandra.db.compaction.CompactionManager;
import org.apache.cassandra.db.view.View;
import org.apache.cassandra.exceptions.SyntaxException;
import org.apache.cassandra.schema.SchemaConstants;
import org.apache.cassandra.schema.SchemaKeyspace;
import org.apache.cassandra.service.ClientWarn;
import org.apache.cassandra.utils.FBUtilities;
import org.awaitility.Awaitility;
Expand All @@ -63,6 +67,7 @@ public class ViewTest extends ViewAbstractTest
/** Latch used by {@link #testTruncateWhileBuilding()} Byteman injections. */
@SuppressWarnings("unused")
private static final CountDownLatch blockViewBuild = new CountDownLatch(1);
private static final AtomicInteger viewNameSeqNumber = new AtomicInteger();

@Test
public void testNonExistingOnes() throws Throwable
Expand Down Expand Up @@ -576,6 +581,100 @@ public void testQuotedIdentifiersInWhereClause() throws Throwable
row("\"theKey\" IS NOT NULL AND (\"theClustering_1\", \"theClustering_2\") = (1, 2) AND \"theValue\" IS NOT NULL"));
}

@Test(expected = SyntaxException.class)
public void emptyViewNameTest() throws Throwable
{
execute("CREATE MATERIALIZED VIEW \"\" AS SELECT a, b FROM tbl WHERE b IS NOT NULL PRIMARY KEY (b, a)");
}

@Test(expected = SyntaxException.class)
public void emptyBaseTableNameTest() throws Throwable
{
execute("CREATE MATERIALIZED VIEW myview AS SELECT a, b FROM \"\" WHERE b IS NOT NULL PRIMARY KEY (b, a)");
}

@Test
public void testFunctionInWhereClause() throws Throwable
{
// Native token function with lowercase, should be unquoted in the schema where clause
assertEmpty(testFunctionInWhereClause("CREATE TABLE %s (k bigint PRIMARY KEY, v int)",
null,
"CREATE MATERIALIZED VIEW %s AS" +
" SELECT * FROM %%s WHERE k = token(1) AND v IS NOT NULL " +
" PRIMARY KEY (v, k)",
"k = token(1) AND v IS NOT NULL",
"INSERT INTO %s(k, v) VALUES (0, 1)",
"INSERT INTO %s(k, v) VALUES (2, 3)"));

// Native token function with uppercase, should be unquoted and lowercased in the schema where clause
assertEmpty(testFunctionInWhereClause("CREATE TABLE %s (k bigint PRIMARY KEY, v int)",
null,
"CREATE MATERIALIZED VIEW %s AS" +
" SELECT * FROM %%s WHERE k = TOKEN(1) AND v IS NOT NULL" +
" PRIMARY KEY (v, k)",
"k = token(1) AND v IS NOT NULL",
"INSERT INTO %s(k, v) VALUES (0, 1)",
"INSERT INTO %s(k, v) VALUES (2, 3)"));

// UDF with lowercase name, shouldn't be quoted in the schema where clause
assertRows(testFunctionInWhereClause("CREATE TABLE %s (k int PRIMARY KEY, v int)",
"CREATE FUNCTION fun()" +
" CALLED ON NULL INPUT" +
" RETURNS int LANGUAGE java" +
" AS 'return 2;'",
"CREATE MATERIALIZED VIEW %s AS " +
" SELECT * FROM %%s WHERE k = fun() AND v IS NOT NULL" +
" PRIMARY KEY (v, k)",
"k = fun() AND v IS NOT NULL",
"INSERT INTO %s(k, v) VALUES (0, 1)",
"INSERT INTO %s(k, v) VALUES (2, 3)"), row(3, 2));

// UDF with uppercase name, should be quoted in the schema where clause
assertRows(testFunctionInWhereClause("CREATE TABLE %s (k int PRIMARY KEY, v int)",
"CREATE FUNCTION \"FUN\"()" +
" CALLED ON NULL INPUT" +
" RETURNS int" +
" LANGUAGE java" +
" AS 'return 2;'",
"CREATE MATERIALIZED VIEW %s AS " +
" SELECT * FROM %%s WHERE k = \"FUN\"() AND v IS NOT NULL" +
" PRIMARY KEY (v, k)",
"k = \"FUN\"() AND v IS NOT NULL",
"INSERT INTO %s(k, v) VALUES (0, 1)",
"INSERT INTO %s(k, v) VALUES (2, 3)"), row(3, 2));

// UDF with uppercase name conflicting with TOKEN keyword but not with native token function name,
// should be quoted in the schema where clause
assertRows(testFunctionInWhereClause("CREATE TABLE %s (k int PRIMARY KEY, v int)",
"CREATE FUNCTION \"TOKEN\"(x int)" +
" CALLED ON NULL INPUT" +
" RETURNS int" +
" LANGUAGE java" +
" AS 'return x;'",
"CREATE MATERIALIZED VIEW %s AS" +
" SELECT * FROM %%s WHERE k = \"TOKEN\"(2) AND v IS NOT NULL" +
" PRIMARY KEY (v, k)",
"k = \"TOKEN\"(2) AND v IS NOT NULL",
"INSERT INTO %s(k, v) VALUES (0, 1)",
"INSERT INTO %s(k, v) VALUES (2, 3)"), row(3, 2));

// UDF with lowercase name conflicting with both TOKEN keyword and native token function name,
// requires specifying the keyspace and should be quoted in the schema where clause
assertRows(testFunctionInWhereClause("CREATE TABLE %s (k int PRIMARY KEY, v int)",
"CREATE FUNCTION \"token\"(x int)" +
" CALLED ON NULL INPUT" +
" RETURNS int" +
" LANGUAGE java" +
" AS 'return x;'",
"CREATE MATERIALIZED VIEW %s AS" +
" SELECT * FROM %%s " +
" WHERE k = " + keyspace() + ".\"token\"(2) AND v IS NOT NULL" +
" PRIMARY KEY (v, k)",
"k = " + keyspace() + ".\"token\"(2) AND v IS NOT NULL",
"INSERT INTO %s(k, v) VALUES (0, 1)",
"INSERT INTO %s(k, v) VALUES (2, 3)"), row(3, 2));
}

/**
* Tests that truncating a table stops the ongoing builds of its materialized views,
* so they don't write into the MV data that has been truncated in the base table.
Expand Down Expand Up @@ -632,4 +731,37 @@ private static int runningViewBuilds()
.map(p -> p.activeTasks.getValue() + p.pendingTasks.getValue())
.orElse(0);
}

private UntypedResultSet testFunctionInWhereClause(String createTableQuery,
String createFunctionQuery,
String createViewQuery,
String expectedSchemaWhereClause,
String... insertQueries) throws Throwable
{
createTable(createTableQuery);

execute("USE " + keyspace());
executeNet("USE " + keyspace());

if (createFunctionQuery != null)
{
execute(createFunctionQuery);
}

String viewName = "view_" + viewNameSeqNumber.getAndIncrement();
createView(viewName, createViewQuery);

// Test the where clause stored in system_schema.views
String schemaQuery = String.format("SELECT where_clause FROM %s.%s WHERE keyspace_name = ? AND view_name = ?",
SchemaConstants.SCHEMA_KEYSPACE_NAME,
SchemaKeyspace.VIEWS);
assertRows(execute(schemaQuery, keyspace(), viewName), row(expectedSchemaWhereClause));

for (String insert : insertQueries)
{
execute(insert);
}

return execute("SELECT * FROM " + viewName);
}
}