Merge branch 'cassandra-4.0' into cassandra-4.1

This commit is contained in:
Stefan Miklosovic 2023-08-21 15:56:46 +02:00
commit 7c7d8f4414
No known key found for this signature in database
GPG Key ID: 32F35CB2F546D93E
4 changed files with 84 additions and 10 deletions

View File

@ -5,6 +5,7 @@ Merged from 4.0:
* Fix BulkLoader ignoring cipher suites options (CASSANDRA-18582)
* Migrate Python optparse to argparse (CASSANDRA-17914)
Merged from 3.11:
* Fix NPE when using udfContext in UDF after a restart of a node (CASSANDRA-18739)
Merged from 3.0:
* CQLSH emits a warning when the server version doesn't match (CASSANDRA-18745)
* Fix missing speculative retries in tablestats (CASSANDRA-18767)

View File

@ -22,12 +22,16 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Supplier;
import com.google.common.base.Suppliers;
import org.apache.cassandra.cql3.ColumnIdentifier;
import org.apache.cassandra.db.marshal.AbstractType;
import org.apache.cassandra.schema.CQLTypeParser;
import org.apache.cassandra.schema.KeyspaceMetadata;
import org.apache.cassandra.cql3.functions.types.*;
import org.apache.cassandra.schema.Schema;
import org.apache.cassandra.utils.ByteBufferUtil;
/**
@ -35,19 +39,25 @@ import org.apache.cassandra.utils.ByteBufferUtil;
*/
public final class UDFContextImpl implements UDFContext
{
private final KeyspaceMetadata keyspaceMetadata;
private final Map<String, TypeCodec<Object>> byName = new HashMap<>();
private final TypeCodec<Object>[] argCodecs;
private final TypeCodec<Object> returnCodec;
private final String keyspace;
UDFContextImpl(List<ColumnIdentifier> argNames, TypeCodec<Object>[] argCodecs, TypeCodec<Object> returnCodec,
KeyspaceMetadata keyspaceMetadata)
/*
metadata can not be retrieved within the constructor as the keyspace itself may be being
constructed and an NPE will result.
*/
private final Supplier<KeyspaceMetadata> metadata;
UDFContextImpl(List<ColumnIdentifier> argNames, TypeCodec<Object>[] argCodecs, TypeCodec<Object> returnCodec, String keyspace)
{
for (int i = 0; i < argNames.size(); i++)
byName.put(argNames.get(i).toString(), argCodecs[i]);
this.argCodecs = argCodecs;
this.returnCodec = returnCodec;
this.keyspaceMetadata = keyspaceMetadata;
this.keyspace = keyspace;
this.metadata = Suppliers.memoize(() -> Schema.instance.getKeyspaceMetadata(keyspace));
}
public UDTValue newArgUDTValue(String argName)
@ -67,9 +77,9 @@ public final class UDFContextImpl implements UDFContext
public UDTValue newUDTValue(String udtName)
{
Optional<org.apache.cassandra.db.marshal.UserType> udtType = keyspaceMetadata.types.get(ByteBufferUtil.bytes(udtName));
Optional<org.apache.cassandra.db.marshal.UserType> udtType = metadata.get().types.get(ByteBufferUtil.bytes(udtName));
DataType dataType = UDHelper.driverType(udtType.orElseThrow(
() -> new IllegalArgumentException("No UDT named " + udtName + " in keyspace " + keyspaceMetadata.name)
() -> new IllegalArgumentException("No UDT named " + udtName + " in keyspace " + keyspace)
));
return newUDTValue(dataType);
}
@ -91,7 +101,7 @@ public final class UDFContextImpl implements UDFContext
public TupleValue newTupleValue(String cqlDefinition)
{
AbstractType<?> abstractType = CQLTypeParser.parse(keyspaceMetadata.name, cqlDefinition, keyspaceMetadata.types);
AbstractType<?> abstractType = CQLTypeParser.parse(keyspace, cqlDefinition, metadata.get().types);
DataType dataType = UDHelper.driverType(abstractType);
return newTupleValue(dataType);
}

View File

@ -234,9 +234,7 @@ public abstract class UDFunction extends AbstractFunction implements ScalarFunct
this.argCodecs = UDHelper.codecsFor(argDataTypes);
this.returnCodec = UDHelper.codecFor(returnDataType);
this.calledOnNullInput = calledOnNullInput;
KeyspaceMetadata keyspaceMetadata = Schema.instance.getKeyspaceMetadata(name.keyspace);
this.udfContext = new UDFContextImpl(argNames, argCodecs, returnCodec,
keyspaceMetadata);
this.udfContext = new UDFContextImpl(argNames, argCodecs, returnCodec, name.keyspace);
}
public static UDFunction tryCreate(FunctionName name,

View File

@ -0,0 +1,65 @@
/*
* 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.distributed.test;
import org.junit.Test;
import org.apache.cassandra.distributed.Cluster;
import static java.lang.Boolean.TRUE;
import static org.apache.cassandra.distributed.api.ConsistencyLevel.ALL;
import static org.apache.cassandra.distributed.shared.AssertUtils.assertRows;
import static org.apache.cassandra.distributed.shared.AssertUtils.row;
public class UDFTest extends TestBaseImpl
{
@Test
public void testUDFContextKeyspaceNotNull() throws Throwable
{
/*
To test the keyspace is not null in the context we call UDFContext.newUDTValue() because it
relies on the keyspace not being null.
*/
String[] createStmts = {
"CREATE TABLE " + KEYSPACE + ".current (city text, PRIMARY KEY (city))",
"CREATE TYPE IF NOT EXISTS " + KEYSPACE + ".aggst (lt int, ge int)",
"CREATE FUNCTION " + KEYSPACE + ".udf_not_null ()\n" +
"CALLED ON NULL INPUT\n" +
"RETURNS boolean LANGUAGE java AS $$\n" +
"udfContext.newUDTValue(\"aggst\");\n" +
"return Boolean.TRUE;\n" +
"$$;",
};
try (Cluster cluster = init(Cluster.create(1, config -> config.set("enable_user_defined_functions", "true"))))
{
for (String stmt : createStmts)
cluster.schemaChange(stmt);
cluster.coordinator(1).execute("INSERT INTO " + KEYSPACE + ".current (city) VALUES ('Helsinki')", ALL);
assertRows(cluster.coordinator(1).execute("SELECT " + KEYSPACE + ".udf_not_null() AS m FROM " + KEYSPACE + ".current", ALL), row(TRUE));
cluster.get(1).shutdown().get();
cluster.get(1).startup();
assertRows(cluster.coordinator(1).execute("SELECT " + KEYSPACE + ".udf_not_null() AS m FROM " + KEYSPACE + ".current", ALL), row(TRUE));
}
}
}